Repository: crawlab-team/crawlab Branch: main Commit: 0485310def8b Files: 766 Total size: 3.3 MB Directory structure: gitextract_torsj7ae/ ├── .dockerignore ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── bug_report_zh.md │ │ ├── feature_request.md │ │ └── feature_request_zh.md │ └── workflows/ │ ├── docker-crawlab-tencent.yml │ └── docker-crawlab.yml ├── .gitignore ├── CHANGELOG-zh.md ├── CHANGELOG.md ├── DISCLAIMER-zh.md ├── DISCLAIMER.md ├── Dockerfile ├── LICENSE ├── README-zh.md ├── README.md ├── SECURITY.md ├── backend/ │ ├── .air.master.conf │ ├── .air.worker.conf │ ├── .editorconfig │ ├── Dockerfile │ ├── README.md │ ├── Taskfile.yml │ ├── bin/ │ │ ├── semver.sh │ │ ├── update-deps.sh │ │ └── update-ver.sh │ ├── conf/ │ │ └── config.yml │ ├── go.mod │ ├── go.mod.dev │ ├── go.mod.local │ ├── go.sum │ ├── main.go │ └── test/ │ ├── config-master.json │ ├── config-worker-01.json │ ├── config-worker-02.json │ ├── config-worker-03.json │ └── config-worker-invalid-auth-key.json ├── bin/ │ ├── docker-init.sh │ ├── gen-ver.sh │ └── update_docker_js_api_address.py ├── changelog/ │ ├── v0.6.0-zh.md │ └── v0.6.0.md ├── core/ │ ├── .editorconfig │ ├── .github/ │ │ └── workflows/ │ │ └── test.yml │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── apps/ │ │ ├── api_v2.go │ │ ├── docker.go │ │ ├── interfaces.go │ │ ├── server_v2.go │ │ └── utils.go │ ├── cmd/ │ │ ├── root.go │ │ ├── server.go │ │ └── server_test.go │ ├── color/ │ │ └── service.go │ ├── config/ │ │ ├── base.go │ │ ├── config.go │ │ ├── config_test.go │ │ └── path.go │ ├── constants/ │ │ ├── action.go │ │ ├── anchor.go │ │ ├── auth.go │ │ ├── cache.go │ │ ├── channels.go │ │ ├── common.go │ │ ├── config_spider.go │ │ ├── data_collection.go │ │ ├── data_field.go │ │ ├── database.go │ │ ├── delegate.go │ │ ├── ds.go │ │ ├── encrypt.go │ │ ├── errors.go │ │ ├── event.go │ │ ├── export.go │ │ ├── file.go │ │ ├── filer.go │ │ ├── filter.go │ │ ├── git.go │ │ ├── grpc.go │ │ ├── http.go │ │ ├── log.go │ │ ├── message.go │ │ ├── node.go │ │ ├── notification.go │ │ ├── pagination.go │ │ ├── register.go │ │ ├── results.go │ │ ├── rpc.go │ │ ├── schedule.go │ │ ├── scrapy.go │ │ ├── signal.go │ │ ├── sort.go │ │ ├── system.go │ │ ├── task.go │ │ ├── user.go │ │ └── variable.go │ ├── container/ │ │ └── container.go │ ├── controllers/ │ │ ├── base_file_v2.go │ │ ├── base_v2.go │ │ ├── base_v2_test.go │ │ ├── export_v2.go │ │ ├── filter_v2.go │ │ ├── http.go │ │ ├── login_v2.go │ │ ├── project_v2.go │ │ ├── result_v2.go │ │ ├── router_v2.go │ │ ├── router_v2_test.go │ │ ├── schedule_v2.go │ │ ├── setting_v2.go │ │ ├── spider_v2.go │ │ ├── spider_v2_test.go │ │ ├── stats_v2.go │ │ ├── sync_v2.go │ │ ├── system_info_v2.go │ │ ├── task_v2.go │ │ ├── token_v2.go │ │ ├── user_v2.go │ │ ├── user_v2_test.go │ │ ├── utils_context.go │ │ ├── utils_filter.go │ │ ├── utils_http.go │ │ ├── utils_pagination.go │ │ ├── utils_sort.go │ │ └── ws_writer.go │ ├── data/ │ │ └── colors.go │ ├── database/ │ │ ├── entity/ │ │ │ └── database.go │ │ ├── interfaces/ │ │ │ ├── database_registry_service.go │ │ │ └── database_service.go │ │ └── registry_service.go │ ├── docker-compose.yml │ ├── docs/ │ │ ├── .gitignore │ │ ├── api/ │ │ │ ├── index.html │ │ │ └── openapi.yaml │ │ ├── package.json │ │ └── scripts/ │ │ └── publish.js │ ├── ds/ │ │ ├── cockroachdb.go │ │ ├── default.go │ │ ├── es.go │ │ ├── kafka.go │ │ ├── mongo.go │ │ ├── mssql.go │ │ ├── mssql_test.go │ │ ├── mysql.go │ │ ├── options.go │ │ ├── postgresql.go │ │ ├── service.go │ │ ├── sql.go │ │ ├── sql_options.go │ │ └── sqlite.go │ ├── entity/ │ │ ├── address.go │ │ ├── color.go │ │ ├── common.go │ │ ├── config_spider.go │ │ ├── data_field.go │ │ ├── dependency.go │ │ ├── doc.go │ │ ├── es.go │ │ ├── event.go │ │ ├── export.go │ │ ├── filter.go │ │ ├── filter_select_option.go │ │ ├── fs_file_info.go │ │ ├── git.go │ │ ├── grpc_base_service_message.go │ │ ├── grpc_base_service_params.go │ │ ├── grpc_delegate_message.go │ │ ├── grpc_event_service_message.go │ │ ├── grpc_subscribe.go │ │ ├── http.go │ │ ├── model_delegate.go │ │ ├── model_info.go │ │ ├── node.go │ │ ├── notification_variable.go │ │ ├── pagination.go │ │ ├── result.go │ │ ├── rpc.go │ │ ├── sort.go │ │ ├── spider.go │ │ ├── stats.go │ │ ├── system_info.go │ │ ├── task.go │ │ ├── translation.go │ │ ├── ttl_map.go │ │ └── version.go │ ├── errors/ │ │ ├── base.go │ │ ├── controller.go │ │ ├── ds.go │ │ ├── event.go │ │ ├── filter.go │ │ ├── fs.go │ │ ├── git.go │ │ ├── grpc.go │ │ ├── http.go │ │ ├── model.go │ │ ├── node.go │ │ ├── process.go │ │ ├── result.go │ │ ├── schedule.go │ │ ├── spider.go │ │ ├── stats.go │ │ ├── store.go │ │ ├── task.go │ │ └── user.go │ ├── event/ │ │ ├── func.go │ │ ├── options.go │ │ └── service.go │ ├── export/ │ │ ├── csv_service.go │ │ ├── csv_service_test.go │ │ └── json_service.go │ ├── fs/ │ │ ├── default.go │ │ ├── service_v2.go │ │ └── service_v2_test.go │ ├── go.mod │ ├── go.sum │ ├── grpc/ │ │ ├── client/ │ │ │ ├── client.go │ │ │ ├── client_v2.go │ │ │ ├── options.go │ │ │ ├── pool.go │ │ │ └── utils_proto.go │ │ ├── middlewares/ │ │ │ └── auth_token.go │ │ ├── payload/ │ │ │ └── model_service_v2_payload.go │ │ └── server/ │ │ ├── dependencies_server_v2.go │ │ ├── message_server.go │ │ ├── metrics_server_v2.go │ │ ├── model_base_service_binder.go │ │ ├── model_base_service_server.go │ │ ├── model_base_service_v2_server.go │ │ ├── model_delegate_binder.go │ │ ├── model_delegate_server.go │ │ ├── node_server.go │ │ ├── node_server_v2.go │ │ ├── server_v2.go │ │ ├── task_server_v2.go │ │ └── utils_handle.go │ ├── i18n/ │ │ └── service.go │ ├── interfaces/ │ │ ├── address.go │ │ ├── color.go │ │ ├── color_service.go │ │ ├── controller_params.go │ │ ├── data_source_service.go │ │ ├── entity.go │ │ ├── event_data.go │ │ ├── event_service.go │ │ ├── export.go │ │ ├── export_service.go │ │ ├── filter.go │ │ ├── filter_condition.go │ │ ├── fs_file_info.go │ │ ├── fs_service.go │ │ ├── fs_service_options.go │ │ ├── fs_service_v2.go │ │ ├── grpc_base.go │ │ ├── grpc_base_service_params.go │ │ ├── grpc_client.go │ │ ├── grpc_client_model_base_service.go │ │ ├── grpc_client_model_delegate.go │ │ ├── grpc_client_model_environment_service.go │ │ ├── grpc_client_model_node_service.go │ │ ├── grpc_client_model_service.go │ │ ├── grpc_client_model_spider_service.go │ │ ├── grpc_client_model_task_service.go │ │ ├── grpc_client_model_task_stat_service.go │ │ ├── grpc_client_pool.go │ │ ├── grpc_model_base_service_message.go │ │ ├── grpc_model_binder.go │ │ ├── grpc_model_delegate_message.go │ │ ├── grpc_model_list_binder.go │ │ ├── grpc_server.go │ │ ├── grpc_stream.go │ │ ├── grpc_subscribe.go │ │ ├── i18n_service.go │ │ ├── injectable.go │ │ ├── list.go │ │ ├── model.go │ │ ├── model_artifact.go │ │ ├── model_artifact_sys.go │ │ ├── model_base_service.go │ │ ├── model_binder.go │ │ ├── model_delegate.go │ │ ├── model_environment.go │ │ ├── model_extra_value.go │ │ ├── model_git.go │ │ ├── model_list_binder.go │ │ ├── model_node.go │ │ ├── model_node_delegate.go │ │ ├── model_permission.go │ │ ├── model_result.go │ │ ├── model_role.go │ │ ├── model_schedule.go │ │ ├── model_service_v2.go │ │ ├── model_spider.go │ │ ├── model_tag.go │ │ ├── model_task.go │ │ ├── model_task_stat.go │ │ ├── model_user.go │ │ ├── model_user_group.go │ │ ├── module.go │ │ ├── node_config_service.go │ │ ├── node_master_service.go │ │ ├── node_service.go │ │ ├── node_service_option.go │ │ ├── node_worker_service.go │ │ ├── options.go │ │ ├── process_daemon.go │ │ ├── provide.go │ │ ├── result_service.go │ │ ├── result_service_mongo.go │ │ ├── result_service_registry.go │ │ ├── schedule_service.go │ │ ├── spider_admin_service.go │ │ ├── spider_service_options.go │ │ ├── stats_service.go │ │ ├── task_base_service.go │ │ ├── task_handler_service.go │ │ ├── task_hook_service.go │ │ ├── task_runner.go │ │ ├── task_scheduler_service.go │ │ ├── task_stats_service.go │ │ ├── test.go │ │ ├── translation.go │ │ ├── user_service.go │ │ ├── user_service_options.go │ │ ├── with_address.go │ │ ├── with_config_path.go │ │ └── with_model_id.go │ ├── main.go │ ├── middlewares/ │ │ ├── auth.go │ │ ├── auth_v2.go │ │ ├── cors.go │ │ ├── filer_auth.go │ │ └── middlewares.go │ ├── models/ │ │ ├── client/ │ │ │ ├── binder_basic.go │ │ │ ├── binder_list.go │ │ │ ├── model_base_service.go │ │ │ ├── model_delegate.go │ │ │ ├── model_environment_service.go │ │ │ ├── model_node_delegate.go │ │ │ ├── model_node_service.go │ │ │ ├── model_service.go │ │ │ ├── model_service_v2.go │ │ │ ├── model_service_v2_test.go │ │ │ ├── model_spider_service.go │ │ │ ├── model_task_service.go │ │ │ ├── model_task_stat_service.go │ │ │ └── options.go │ │ ├── common/ │ │ │ └── index_service_v2.go │ │ ├── config_spider/ │ │ │ ├── common.go │ │ │ └── scrapy.go │ │ ├── delegate/ │ │ │ ├── base_test.go │ │ │ ├── model.go │ │ │ ├── model_node.go │ │ │ ├── model_node_test.go │ │ │ ├── model_role_test.go │ │ │ ├── model_test.go │ │ │ └── utils_event.go │ │ ├── models/ │ │ │ ├── artifact.go │ │ │ ├── artifact_sys.go │ │ │ ├── base.go │ │ │ ├── data_collection.go │ │ │ ├── data_source.go │ │ │ ├── dependency_setting.go │ │ │ ├── environment.go │ │ │ ├── extra_value.go │ │ │ ├── git.go │ │ │ ├── job.go │ │ │ ├── node.go │ │ │ ├── password.go │ │ │ ├── permission.go │ │ │ ├── project.go │ │ │ ├── result.go │ │ │ ├── role.go │ │ │ ├── role_permission.go │ │ │ ├── schedule.go │ │ │ ├── setting.go │ │ │ ├── spider.go │ │ │ ├── spider_stat.go │ │ │ ├── tag.go │ │ │ ├── task.go │ │ │ ├── task_queue_item.go │ │ │ ├── task_stat.go │ │ │ ├── token.go │ │ │ ├── user.go │ │ │ ├── user_role.go │ │ │ ├── utils_binder_legacy.go │ │ │ ├── utils_col.go │ │ │ ├── utils_model_map.go │ │ │ ├── utils_tag.go │ │ │ ├── v2/ │ │ │ │ ├── base_v2.go │ │ │ │ ├── data_collection_v2.go │ │ │ │ ├── database_metric_v2.go │ │ │ │ ├── database_v2.go │ │ │ │ ├── dependency_log_v2.go │ │ │ │ ├── dependency_setting_v2.go │ │ │ │ ├── dependency_task_v2.go │ │ │ │ ├── dependency_v2.go │ │ │ │ ├── environment_v2.go │ │ │ │ ├── git_v2.go │ │ │ │ ├── metric_v2.go │ │ │ │ ├── node_v2.go │ │ │ │ ├── notification_alert_v2.go │ │ │ │ ├── notification_channel_v2.go │ │ │ │ ├── notification_request_v2.go │ │ │ │ ├── notification_setting_v2.go │ │ │ │ ├── permission_v2.go │ │ │ │ ├── project_v2.go │ │ │ │ ├── role_permission_v2.go │ │ │ │ ├── role_v2.go │ │ │ │ ├── schedule_v2.go │ │ │ │ ├── setting_v2.go │ │ │ │ ├── spider_stat_v2.go │ │ │ │ ├── spider_v2.go │ │ │ │ ├── task_queue_item_v2.go │ │ │ │ ├── task_stat_v2.go │ │ │ │ ├── task_v2.go │ │ │ │ ├── test_v2.go │ │ │ │ ├── token_v2.go │ │ │ │ ├── user_role_v2.go │ │ │ │ ├── user_v2.go │ │ │ │ └── variable_v2.go │ │ │ └── variable.go │ │ └── service/ │ │ ├── artifact_service.go │ │ ├── base_service.go │ │ ├── base_service_v2.go │ │ ├── base_service_v2_test.go │ │ ├── binder_basic.go │ │ ├── binder_list.go │ │ ├── data_collection_service.go │ │ ├── data_source_service.go │ │ ├── dependency_setting_service.go │ │ ├── environment_service.go │ │ ├── extra_value_service.go │ │ ├── git_service.go │ │ ├── interface.go │ │ ├── job_service.go │ │ ├── node_service.go │ │ ├── options.go │ │ ├── password_service.go │ │ ├── permission_service.go │ │ ├── project_service.go │ │ ├── role_permission_service.go │ │ ├── role_service.go │ │ ├── schedule_service.go │ │ ├── service.go │ │ ├── setting_service.go │ │ ├── spider_service.go │ │ ├── spider_stat_service.go │ │ ├── tag_service.go │ │ ├── tag_service_legacy.go │ │ ├── task_queue_service.go │ │ ├── task_service.go │ │ ├── task_stat_service.go │ │ ├── token_service.go │ │ ├── user_role_service.go │ │ ├── user_service.go │ │ └── variable_service.go │ ├── node/ │ │ ├── config/ │ │ │ ├── config.go │ │ │ ├── config_service.go │ │ │ └── options.go │ │ └── service/ │ │ ├── master_service_v2.go │ │ ├── options.go │ │ └── worker_service_v2.go │ ├── notification/ │ │ ├── constants.go │ │ ├── entity.go │ │ ├── im.go │ │ ├── mail.go │ │ ├── mail_gmail.go │ │ ├── oauth2_gmail.go │ │ ├── service_v2.go │ │ ├── service_v2_test.go │ │ └── theme.go │ ├── process/ │ │ ├── daemon.go │ │ ├── daemon_test.go │ │ ├── manage.go │ │ └── options.go │ ├── result/ │ │ ├── options.go │ │ ├── service.go │ │ ├── service_mongo.go │ │ └── service_registry.go │ ├── schedule/ │ │ ├── logger.go │ │ ├── options.go │ │ ├── service.go │ │ ├── service_v2.go │ │ └── test/ │ │ ├── base.go │ │ └── schedule_service_test.go │ ├── spider/ │ │ └── admin/ │ │ ├── options.go │ │ ├── service.go │ │ └── service_v2.go │ ├── stats/ │ │ ├── options.go │ │ └── service.go │ ├── sys_exec/ │ │ ├── sys_exec.go │ │ ├── sys_exec_darwin.go │ │ ├── sys_exec_linux.go │ │ └── sys_exec_windows.go │ ├── system/ │ │ ├── service.go │ │ └── service_v2.go │ ├── task/ │ │ ├── handler/ │ │ │ ├── options.go │ │ │ ├── runner_test.go │ │ │ ├── runner_v2.go │ │ │ └── service_v2.go │ │ ├── log/ │ │ │ ├── constants.go │ │ │ ├── default.go │ │ │ ├── driver.go │ │ │ ├── entity.go │ │ │ ├── errors.go │ │ │ ├── file_driver.go │ │ │ ├── file_driver_test.go │ │ │ └── interface.go │ │ ├── scheduler/ │ │ │ ├── options.go │ │ │ └── service_v2.go │ │ └── stats/ │ │ ├── options.go │ │ └── service_v2.go │ ├── user/ │ │ ├── options.go │ │ ├── service.go │ │ ├── service_v2.go │ │ └── test/ │ │ ├── base.go │ │ └── user_service_test.go │ └── utils/ │ ├── args.go │ ├── array.go │ ├── backoff.go │ ├── binders/ │ │ └── binder_col_name.go │ ├── bool.go │ ├── bson.go │ ├── cache.go │ ├── chan.go │ ├── chan_test.go │ ├── cockroachdb.go │ ├── cron.go │ ├── debug.go │ ├── demo.go │ ├── di.go │ ├── docker.go │ ├── encrypt.go │ ├── encrypt_test.go │ ├── es.go │ ├── file.go │ ├── file_test.go │ ├── filter.go │ ├── git.go │ ├── hash.go │ ├── helpers.go │ ├── http.go │ ├── init.go │ ├── json.go │ ├── kafka.go │ ├── mongo.go │ ├── mssql.go │ ├── mysql.go │ ├── node.go │ ├── os.go │ ├── postgresql.go │ ├── result.go │ ├── rpc.go │ ├── spider.go │ ├── sql.go │ ├── sqlite.go │ ├── stats.go │ ├── system.go │ ├── task.go │ ├── time.go │ └── uuid.go ├── db/ │ ├── .editorconfig │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── errors/ │ │ ├── base.go │ │ ├── errors.go │ │ └── redis.go │ ├── generic/ │ │ ├── base.go │ │ ├── list.go │ │ ├── op.go │ │ └── sort.go │ ├── go.mod │ ├── interfaces.go │ ├── mongo/ │ │ ├── client.go │ │ ├── client_options.go │ │ ├── client_test.go │ │ ├── col.go │ │ ├── col_test.go │ │ ├── db.go │ │ ├── db_options.go │ │ ├── db_test.go │ │ ├── result.go │ │ └── transaction.go │ ├── redis/ │ │ ├── client.go │ │ ├── constants.go │ │ ├── options.go │ │ ├── pool.go │ │ └── test/ │ │ ├── base.go │ │ └── client_test.go │ ├── sql/ │ │ └── sql.go │ └── utils/ │ └── utils.go ├── devops/ │ ├── develop/ │ │ ├── crawlab-master.yaml │ │ ├── crawlab-worker.yaml │ │ ├── mongo-pv.yaml │ │ ├── mongo.yaml │ │ ├── ns.yaml │ │ └── redis.yaml │ ├── master/ │ │ ├── crawlab-master.yaml │ │ ├── crawlab-worker.yaml │ │ ├── mongo-pv.yaml │ │ ├── mongo.yaml │ │ ├── ns.yaml │ │ └── redis.yaml │ └── release/ │ ├── crawlab-master.yaml │ ├── crawlab-worker.yaml │ ├── mongo-pv.yaml │ ├── mongo.yaml │ ├── ns.yaml │ └── redis.yaml ├── docker-compose.yml ├── docs/ │ └── config.md ├── frontend/ │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmrc │ ├── Dockerfile │ ├── babel.config.js │ ├── index.html │ ├── jest.config.ts │ ├── package.json │ ├── public/ │ │ ├── fonts/ │ │ │ └── FontAwesome.otf │ │ └── js/ │ │ ├── login-canvas.js │ │ └── vue3-sfc-loader.js │ ├── src/ │ │ ├── main.ts │ │ └── shims-vue.d.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vue.config.js ├── fs/ │ ├── .editorconfig │ ├── .github/ │ │ └── workflows/ │ │ └── test.yml │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── bin/ │ │ ├── start.sh │ │ └── stop.sh │ ├── constants.go │ ├── docker-compose.yml │ ├── errors.go │ ├── go.mod │ ├── go.sum │ ├── interface.go │ ├── lib/ │ │ └── copy/ │ │ └── copy.go │ ├── options.go │ ├── seaweedfs_manager.go │ ├── test/ │ │ ├── base.go │ │ ├── bindata.go │ │ ├── main_test.go │ │ ├── seaweedfs_test.go │ │ └── utils.go │ └── utils.go ├── go.work ├── go.work.sum ├── grpc/ │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── bin/ │ │ ├── compile.sh │ │ └── compile_all.sh │ ├── dependencies_service_v2.pb.go │ ├── dependencies_service_v2_grpc.pb.go │ ├── go.mod │ ├── go.sum │ ├── message_service.pb.go │ ├── message_service_grpc.pb.go │ ├── metrics_service_v2.pb.go │ ├── metrics_service_v2_grpc.pb.go │ ├── model_base_service.pb.go │ ├── model_base_service_grpc.pb.go │ ├── model_base_service_v2.pb.go │ ├── model_base_service_v2_grpc.pb.go │ ├── model_delegate.pb.go │ ├── model_delegate_grpc.pb.go │ ├── model_service_v2_request.pb.go │ ├── node.pb.go │ ├── node_info.pb.go │ ├── node_service.pb.go │ ├── node_service_grpc.pb.go │ ├── plugin_request.pb.go │ ├── plugin_service.pb.go │ ├── plugin_service_grpc.pb.go │ ├── proto/ │ │ ├── entity/ │ │ │ ├── model_service_v2_request.proto │ │ │ ├── node_info.proto │ │ │ ├── plugin_request.proto │ │ │ ├── request.proto │ │ │ ├── response.proto │ │ │ ├── response_code.proto │ │ │ ├── stream_message.proto │ │ │ ├── stream_message_code.proto │ │ │ └── stream_message_data_task.proto │ │ ├── models/ │ │ │ ├── node.proto │ │ │ └── task.proto │ │ └── services/ │ │ ├── dependencies_service_v2.proto │ │ ├── message_service.proto │ │ ├── metrics_service_v2.proto │ │ ├── model_base_service.proto │ │ ├── model_base_service_v2.proto │ │ ├── model_delegate.proto │ │ ├── node_service.proto │ │ ├── plugin_service.proto │ │ └── task_service.proto │ ├── request.pb.go │ ├── response.pb.go │ ├── response_code.pb.go │ ├── stream_message.pb.go │ ├── stream_message_code.pb.go │ ├── stream_message_data_task.pb.go │ ├── task.pb.go │ ├── task_service.pb.go │ └── task_service_grpc.pb.go ├── k8s/ │ ├── crawlab-master.yaml │ ├── crawlab-worker.yaml │ ├── mongo-pv.yaml │ ├── mongo.yaml │ ├── ns.yaml │ └── redis.yaml ├── nginx/ │ └── crawlab.conf ├── scripts/ │ └── validate-backend.sh ├── template-parser/ │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── entity.go │ ├── func.go │ ├── general_parser.go │ ├── go.mod │ ├── go.sum │ ├── interfaces.go │ ├── parser.go │ ├── test/ │ │ └── general_parser_test.go │ └── variable.go ├── trace/ │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── go.mod │ ├── go.sum │ └── trace.go ├── vcs/ │ ├── .github/ │ │ └── workflows/ │ │ └── test.yml │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── constants.go │ ├── entity.go │ ├── errors.go │ ├── git.go │ ├── git_options.go │ ├── git_store.go │ ├── git_utils.go │ ├── go.mod │ ├── go.sum │ ├── interface.go │ ├── test/ │ │ ├── base.go │ │ ├── credential.go │ │ ├── credentials.example.json │ │ └── git_test.go │ └── utils.go └── workspace/ ├── .gitignore ├── docker-compose.yml ├── dockerfiles/ │ ├── golang/ │ │ └── Dockerfile │ └── node/ │ ├── .dockerignore │ └── Dockerfile └── localdev/ ├── README.md └── docker-compose.yml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ .idea logs *.log dist/ **/node_modules/ **/tmp/ **/vendor/ .github/ .devops k8s workspace .git/ ================================================ FILE: .gitattributes ================================================ *.md linguist-language=Go *.yml linguist-language=Go *.html linguist-language=Go *.js linguist-language=Go *.ts linguist-language=Go *.vue linguist-language=Go *.xml linguist-language=Go *.css linguist-language=Go *.sql linguist-language=Go *.uml linguist-language=Go *.cmd linguist-language=Go ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: 'bug' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report_zh.md ================================================ --- name: Bug 报告 about: 创建一份 Bug 报告帮助我们优化产品 title: '' labels: 'bug' assignees: '' --- **Bug 描述** 例如,当 xxx 时,xxx 功能不工作。 **复现步骤** 该 Bug 复现步骤如下 1. 2. 3. **期望结果** xxx 能工作。 **截屏** ![截屏1](http://static-docs.crawlab.cn/login.png) ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: 'enhancement' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request_zh.md ================================================ --- name: 功能需求 about: 优化和功能需求建议 title: '' labels: 'enhancement' assignees: '' --- **请描述该需求尝试解决的问题** 例如,当 xxx 时,我总是被当前 xxx 的设计所困扰。 **请描述您认为可行的解决方案** 例如,添加 xxx 功能能够解决问题。 **考虑过的替代方案** 例如,如果用 xxx,也能解决该问题。 ================================================ FILE: .github/workflows/docker-crawlab-tencent.yml ================================================ name: "Docker Image CI: crawlab (tencent)" on: push: branches: [ develop, main ] #pull_request: # branches: [ main ] release: types: [ published ] workflow_dispatch: repository_dispatch: types: [ docker-crawlab ] env: IMAGE_PATH_CRAWLAB_BACKEND: backend IMAGE_PATH_CRAWLAB_FRONTEND: frontend IMAGE_NAME_CRAWLAB: ccr.ccs.tencentyun.com/crawlab/crawlab IMAGE_NAME_CRAWLAB_BACKEND: crawlabteam/crawlab-backend IMAGE_NAME_CRAWLAB_FRONTEND: crawlabteam/crawlab-frontend jobs: setup: runs-on: ubuntu-latest outputs: is_matched_backend: ${{ steps.check_changed_files.outputs.is_matched_backend }} is_matched_frontend: ${{ steps.check_changed_files.outputs.is_matched_frontend }} is_matched_dockerfile: ${{ steps.check_changed_files.outputs.is_matched_dockerfile }} version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v2 - name: Get changed files id: changed_files uses: tj-actions/changed-files@v18.7 - id: check_changed_files name: Check changed files run: | # check changed files is_matched_backend=0 is_matched_frontend=0 is_matched_dockerfile=0 for file in ${{ steps.changed_files.outputs.all_changed_files }}; do if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_BACKEND}/.* ]]; then file_backend=$file is_matched_backend=1 fi if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_FRONTEND}/.* ]]; then file_frontend=$file is_matched_frontend=1 fi if [[ $file == Dockerfile ]]; then file_dockerfile=$file is_matched_dockerfile=1 fi done # set outputs if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then is_matched_backend=1 is_matched_frontend=1 is_matched_dockerfile=1 fi echo "::set-output name=is_matched_backend::$is_matched_backend" echo "::set-output name=is_matched_frontend::$is_matched_frontend" echo "::set-output name=is_matched_dockerfile::$is_matched_dockerfile" # echo outputs echo "is_matched_backend=$is_matched_backend, file_backend=$file_backend" echo "is_matched_frontend=$is_matched_frontend, file_frontend=$file_frontend" echo "is_matched_dockerfile=$is_matched_dockerfile, file_dockerfile=$file_dockerfile" - id: version name: Get version run: | # Strip git ref prefix from version VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # Strip "v" prefix from tag name [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') # Use Docker `latest` tag convention [ "$VERSION" == "main" ] && VERSION=latest echo "::set-output name=version::$VERSION" build-backend: needs: [ setup ] if: needs.setup.outputs.is_matched_backend == '1' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Get changed files id: changed-files uses: tj-actions/changed-files@v18.7 - name: Build image run: | cd $IMAGE_PATH_CRAWLAB_BACKEND docker build . --file Dockerfile --tag image - name: Log into registry run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_NAME=$IMAGE_NAME_CRAWLAB_BACKEND docker tag image $IMAGE_NAME:$IMAGE_VERSION docker push $IMAGE_NAME:$IMAGE_VERSION build-frontend: needs: [ setup ] if: needs.setup.outputs.is_matched_frontend == '1' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Get changed files id: changed-files uses: tj-actions/changed-files@v18.7 - name: Build image run: | cd $IMAGE_PATH_CRAWLAB_FRONTEND docker build . --file Dockerfile --tag image - name: Log into registry run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_NAME=$IMAGE_NAME_CRAWLAB_FRONTEND docker tag image $IMAGE_NAME:$IMAGE_VERSION docker push $IMAGE_NAME:$IMAGE_VERSION build-crawlab: if: ${{ always() }} needs: [ setup, build-backend, build-frontend ] runs-on: ubuntu-latest services: mongo: image: mongo:4.2 ports: - 27017:27017 steps: - uses: actions/checkout@v2 - name: Update Dockerfile run: | IMAGE_VERSION=${{needs.setup.outputs.version}} if [[ $IMAGE_VERSION != "latest" ]]; then for n in crawlab-backend crawlab-frontend; do IMAGE_NAME=$n sed -i "s/${IMAGE_NAME}:latest/${IMAGE_NAME}:${IMAGE_VERSION}/" Dockerfile done fi - name: Build image run: docker build . --file Dockerfile --tag image - name: Test image run: | docker run --rm -d --name crawlab_master \ -e CRAWLAB_NODE_MASTER=true \ -e CRAWLAB_DEMO=true \ -e CRAWLAB_MONGO_HOST=localhost \ -e CRAWLAB_MONGO_PORT=27017 \ -p 8080:8080 \ --network host \ image docker exec crawlab_master env docker logs -f crawlab_master & sleep 10 docker ps cmd='curl http://localhost:8080/api/system-info -s' echo "cmd: ${cmd}" res=`${cmd}` echo "res: ${res}" if [[ $res =~ "success" ]]; then : else exit 1 fi docker stop crawlab_master - name: Set up Python uses: actions/setup-python@v1 with: python-version: '3.8' - name: Test demo run: | pip install crawlab-demo crawlab-demo validate - name: Log into registry run: echo ${{ secrets.DOCKER_TENCENT_PASSWORD }} | docker login -u ${{ secrets.DOCKER_TENCENT_USERNAME }} --password-stdin ccr.ccs.tencentyun.com - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_ID=$IMAGE_NAME_CRAWLAB docker tag image $IMAGE_ID:$IMAGE_VERSION docker push $IMAGE_ID:$IMAGE_VERSION ================================================ FILE: .github/workflows/docker-crawlab.yml ================================================ name: "Docker Image CI: crawlab" on: push: branches: [ develop, main ] #pull_request: # branches: [ main ] release: types: [ published ] workflow_dispatch: repository_dispatch: types: [ docker-crawlab ] env: IMAGE_PATH_CRAWLAB_BACKEND: backend IMAGE_PATH_CRAWLAB_FRONTEND: frontend IMAGE_NAME_CRAWLAB: crawlabteam/crawlab IMAGE_NAME_CRAWLAB_BACKEND: crawlabteam/crawlab-backend IMAGE_NAME_CRAWLAB_FRONTEND: crawlabteam/crawlab-frontend jobs: setup: runs-on: ubuntu-latest outputs: is_matched_backend: ${{ steps.check_changed_files.outputs.is_matched_backend }} is_matched_frontend: ${{ steps.check_changed_files.outputs.is_matched_frontend }} is_matched_dockerfile: ${{ steps.check_changed_files.outputs.is_matched_dockerfile }} version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v2 - name: Get changed files id: changed_files uses: tj-actions/changed-files@v18.7 - id: check_changed_files name: Check changed files run: | # check changed files is_matched_backend=0 is_matched_frontend=0 is_matched_dockerfile=0 for file in ${{ steps.changed_files.outputs.all_changed_files }}; do if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_BACKEND}/.* ]]; then file_backend=$file is_matched_backend=1 fi if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_FRONTEND}/.* ]]; then file_frontend=$file is_matched_frontend=1 fi if [[ $file == Dockerfile ]]; then file_dockerfile=$file is_matched_dockerfile=1 fi done # set outputs if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then is_matched_backend=1 is_matched_frontend=1 is_matched_dockerfile=1 fi echo "::set-output name=is_matched_backend::$is_matched_backend" echo "::set-output name=is_matched_frontend::$is_matched_frontend" echo "::set-output name=is_matched_dockerfile::$is_matched_dockerfile" # echo outputs echo "is_matched_backend=$is_matched_backend, file_backend=$file_backend" echo "is_matched_frontend=$is_matched_frontend, file_frontend=$file_frontend" echo "is_matched_dockerfile=$is_matched_dockerfile, file_dockerfile=$file_dockerfile" - id: version name: Get version run: | # Strip git ref prefix from version VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # Strip "v" prefix from tag name [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') # Use Docker `latest` tag convention [ "$VERSION" == "main" ] && VERSION=latest echo "::set-output name=version::$VERSION" build-backend: needs: [ setup ] if: needs.setup.outputs.is_matched_backend == '1' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Get changed files id: changed-files uses: tj-actions/changed-files@v18.7 - name: Build image run: | cd $IMAGE_PATH_CRAWLAB_BACKEND docker build . --file Dockerfile --tag image - name: Log into registry run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_NAME=$IMAGE_NAME_CRAWLAB_BACKEND docker tag image $IMAGE_NAME:$IMAGE_VERSION docker push $IMAGE_NAME:$IMAGE_VERSION build-frontend: needs: [ setup ] if: needs.setup.outputs.is_matched_frontend == '1' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Get changed files id: changed-files uses: tj-actions/changed-files@v18.7 - name: Build image run: | cd $IMAGE_PATH_CRAWLAB_FRONTEND docker build . --file Dockerfile --tag image - name: Log into registry run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_NAME=$IMAGE_NAME_CRAWLAB_FRONTEND docker tag image $IMAGE_NAME:$IMAGE_VERSION docker push $IMAGE_NAME:$IMAGE_VERSION build-crawlab: if: ${{ always() }} needs: [ setup, build-backend, build-frontend ] runs-on: ubuntu-latest services: mongo: image: mongo:4.2 ports: - 27017:27017 steps: - uses: actions/checkout@v2 - name: Update Dockerfile run: | IMAGE_VERSION=${{needs.setup.outputs.version}} if [[ $IMAGE_VERSION != "latest" ]]; then for n in crawlab-backend crawlab-frontend; do IMAGE_NAME=$n sed -i "s/${IMAGE_NAME}:latest/${IMAGE_NAME}:${IMAGE_VERSION}/" Dockerfile done fi - name: Build image run: docker build . --file Dockerfile --tag image - name: Test image run: | docker run --rm -d --name crawlab_master \ -e CRAWLAB_NODE_MASTER=true \ -e CRAWLAB_DEMO=true \ -e CRAWLAB_MONGO_HOST=localhost \ -e CRAWLAB_MONGO_PORT=27017 \ -p 8080:8080 \ --network host \ image docker exec crawlab_master env docker logs -f crawlab_master & sleep 10 docker ps cmd='curl http://localhost:8080/api/system-info -s' echo "cmd: ${cmd}" res=`${cmd}` echo "res: ${res}" if [[ $res =~ "success" ]]; then : else exit 1 fi docker stop crawlab_master - name: Set up Python uses: actions/setup-python@v1 with: python-version: '3.8' - name: Test demo run: | pip install crawlab-demo crawlab-demo validate - name: Log into registry run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - name: Push image run: | IMAGE_VERSION=${{needs.setup.outputs.version}} IMAGE_ID=$IMAGE_NAME_CRAWLAB docker tag image $IMAGE_ID:$IMAGE_VERSION docker push $IMAGE_ID:$IMAGE_VERSION ================================================ FILE: .gitignore ================================================ .idea/ .vscode/ .DS_Store node_modules/ logs/ tmp/ _book/ *.lock vendor/ .crawlab dist/ ================================================ FILE: CHANGELOG-zh.md ================================================ # 0.6.0 (TBC) (TBC) # 0.5.1 (2020-07-31) ### 功能 / 优化 - **加入错误详情信息**. - **加入 Golang 编程语言支持**. - **加入 Chrome Driver 和 Firefox 的 Web Driver 安装脚本**. - **支持系统任务**. "系统任务"跟普通爬虫任务相似,允许用户查看诸如安装语言之类的任务日志. - **将安装语言从 RPC 更改为系统任务**. ### Bug 修复 - **修复在爬虫市场中第一次下载爬虫时会报500错误**. [#808](https://github.com/crawlab-team/crawlab/issues/808) - **修复一部分翻译问题**. - **修复任务详情 500 错误**. [#810](https://github.com/crawlab-team/crawlab/issues/810) - **修复密码重置问题**. [#811](https://github.com/crawlab-team/crawlab/issues/811) - **修复无法下载 CSV 问题**. [#812](https://github.com/crawlab-team/crawlab/issues/812) - **修复无法安装 Node.js 问题**. [#813](https://github.com/crawlab-team/crawlab/issues/813) - **修复批量添加定时任务时默认为禁用问题**. [#814](https://github.com/crawlab-team/crawlab/issues/814) # 0.5.0 (2020-07-19) ### 功能 / 优化 - **爬虫市场**. 允许用户下载开源爬虫到 Crawlab. - **批量操作**. 允许用户与 Crawlab 批量交互,例如批量运行任务、批量删除爬虫等等. - **迁移 MongoDB 驱动器至 `MongoDriver`**. - **重构优化节点逻辑代码**. - **更改默认 `task.workers` 至 16**. - **更改默认 nginx `client_max_body_size` 为 200m**. - **支持写日志到 ElasticSearch**. - **在 Scrapy 页面展示错误详情**. - **删除挑战页面**. - **将反馈、免责声明页面移动到顶部**. ### Bug 修复 - **修复由于 TTL 索引未创建导致的日志不过期问题**. - **设置默认日志过期时间为 1 天**. - **`task_id` 索引没有创建**. - **`docker-compose.yml` 修复**. - **修复 404 页面**. - **修复无法先创建工作节点问题**. # 0.4.10 (2020-04-21) ### 功能 / 优化 - **优化日志管理**. 集中化管理日志,储存在 MongoDB,减少对 PubSub 的依赖,允许日志异常检测. - **自动安装依赖**. 允许从 `requirements.txt` 和 `package.json` 自动安装依赖. - **API Token**. 允许用户生成 API Token,并利用它们来集成到自己的系统中. - **Web Hook**. 当任务开始或结束时,触发 Web Hook http 请求到预定义好的 URL. - **自动生成结果集**. 如果没有设置,自动设置结果集为 `results_`. - **优化项目列表**. 项目列表中不展示 "No Project". - **升级 Node.js**. 将 Node.js 版本从 v8.12 升级到 v10.19. - **定时任务增加运行按钮**. 允许用户在定时任务界面手动运行爬虫任务. ### Bug 修复 - **无法注册**. [#670](https://github.com/crawlab-team/crawlab/issues/670) - **爬虫定时任务标签 Cron 表达式显示秒**. [#678](https://github.com/crawlab-team/crawlab/issues/678) - **爬虫每日数据缺失**. [#684](https://github.com/crawlab-team/crawlab/issues/684) - **结果数量未即时更新**. [#689](https://github.com/crawlab-team/crawlab/issues/689) # 0.4.9 (2020-03-31) ### 功能 / 优化 - **挑战**. 用户可以完成不同的趣味挑战.. - **更高级的权限控制**. 更细化的权限管理,例如普通用户只能查看或管理自己的爬虫或项目,而管理用户可以查看或管理所有爬虫或项目. - **反馈**. 允许用户发送反馈和评分给 Crawlab 开发组. - **更好的主页指标**. 优化主页上的指标展示. - **可配置爬虫转化为自定义爬虫**. 用户可以将自己的可配置爬虫转化为 Scrapy 自定义爬虫. - **查看定时任务触发的任务**. 允许用户查看定时任务触发的任务. [#648](https://github.com/crawlab-team/crawlab/issues/648) - **支持结果去重**. 允许用户配置结果去重. [#579](https://github.com/crawlab-team/crawlab/issues/579) - **支持任务重试**. 允许任务重新触发历史任务. ### Bug 修复 - **无法注册**. [#670](https://github.com/crawlab-team/crawlab/issues/670) - **CLI 无法在 Windows 上使用**. [#580](https://github.com/crawlab-team/crawlab/issues/580) - **重新上传错误**. [#643](https://github.com/crawlab-team/crawlab/issues/643) [#640](https://github.com/crawlab-team/crawlab/issues/640) - **上传丢失文件目录**. [#646](https://github.com/crawlab-team/crawlab/issues/646) - **无法在爬虫定时任务标签中添加定时任务**. # 0.4.8 (2020-03-11) ### 功能 / 优化 - **支持更多编程语言安装**. 现在用户可以安装或预装更多的编程语言,包括 Java、.Net Core、PHP. - **安装 UI 优化**. 用户能够更好的查看和管理节点列表页的安装. - **更多 Git 支持**. 允许用户查看 Git Commits 记录,并 Checkout 到相应 Commit. - **支持用 Hostname 作为节点注册类型**. 用户可以将 hostname 作为节点的唯一识别号. - **RPC 支持**. 加入 RPC 支持来更好的管理节点通信. - **是否在主节点运行开关**. 用户可以决定是否在主节点运行,如果为否,则所有任务将在工作节点上运行. - **默认禁用教程**. - **加入相关文档侧边栏**. - **加载页面优化**. ### Bug 修复 - **重复节点**. [#391](https://github.com/crawlab-team/crawlab/issues/391) - **重复上传爬虫**. [#603](https://github.com/crawlab-team/crawlab/issues/603) - **节点第三方模块安装失败导致 节点安装第三方部分无法使用**. [#609](https://github.com/crawlab-team/crawlab/issues/609) - **离线节点也会创建任务**. [#622](https://github.com/crawlab-team/crawlab/issues/622) # 0.4.7 (2020-02-24) ### 功能 / 优化 - **更好的支持 Scrapy**. 爬虫识别,`settings.py` 配置,日志级别选择,爬虫选择. [#435](https://github.com/crawlab-team/crawlab/issues/435) - **Git 同步**. 允许用户将 Git 项目同步到 Crawlab. - **长任务支持**. 用户可以添加长任务爬虫,这些爬虫可以跑长期运行的任务. [425](https://github.com/crawlab-team/crawlab/issues/425) - **爬虫列表优化**. 分状态任务列数统计,任务列表详情弹出框,图例. [425](https://github.com/crawlab-team/crawlab/issues/425) - **版本升级检测**. 检测最新版本,通知用户升级. - **批量操作爬虫**. 允许用户批量运行/停止爬虫任务,以及批量删除爬虫. - **复制爬虫**. 允许用户复制已存在爬虫来创建新爬虫. - **微信群二维码**. ### Bug 修复 - **定时任务爬虫选择问题**. 字段不会随着爬虫变化而响应. - **定时任务冲突问题**. 两个不同的爬虫设置定时任务,时间设置成相同的话,可能会有bug. [#515](https://github.com/crawlab-team/crawlab/issues/515) [#565](https://github.com/crawlab-team/crawlab/issues/565) - **任务日志问题**. 在同一时间触发的不同任务可能会写入同一个日志文件. [#577](https://github.com/crawlab-team/crawlab/issues/577) - **任务列表筛选选项不全**. # 0.4.6 (2020-02-13) ### 功能 / 优化 - **Node.js SDK**. 用户可以将 SDK 应用到他们的 Node.js 爬虫中. - **日志管理优化**. 日志搜索,错误高亮,自动滚动. - **任务执行流程优化**. 允许用户在触发任务后跳转到该任务详情页. - **任务展示优化**. 在爬虫详情页的最近任务表格中加入了“参数”列. [#295](https://github.com/crawlab-team/crawlab/issues/295) - **爬虫列表优化**. 在爬虫列表页加入"更新时间"和"创建时间". [#505](https://github.com/crawlab-team/crawlab/issues/505) - **页面加载占位器**. ### Bug 修复 - **定时任务配置失去焦点**. [#519](https://github.com/crawlab-team/crawlab/issues/519) - **无法用 CLI 工具上传爬虫**. [#524](https://github.com/crawlab-team/crawlab/issues/524) # 0.4.5 (2020-02-03) ### 功能 / 优化 - **交互式教程**. 引导用户了解 Crawlab 的主要功能. - **加入全局环境变量**. 可以设置全局环境变量,然后传入到所有爬虫程序中. [#177](https://github.com/crawlab-team/crawlab/issues/177) - **项目**. 允许用户将爬虫关联到项目上. [#316](https://github.com/crawlab-team/crawlab/issues/316) - **示例爬虫**. 当初始化时,自动加入示例爬虫. [#379](https://github.com/crawlab-team/crawlab/issues/379) - **用户管理优化**. 限制管理用户的权限. [#456](https://github.com/crawlab-team/crawlab/issues/456) - **设置页面优化**. - **任务结果页面优化**. ### Bug 修复 - **无法找到爬虫文件错误**. [#485](https://github.com/crawlab-team/crawlab/issues/485) - **点击删除按钮导致跳转**. [#480](https://github.com/crawlab-team/crawlab/issues/480) - **无法在空爬虫里创建文件**. [#479](https://github.com/crawlab-team/crawlab/issues/479) - **下载结果错误**. [#465](https://github.com/crawlab-team/crawlab/issues/465) - **crawlab-sdk CLI 错误**. [#458](https://github.com/crawlab-team/crawlab/issues/458) - **页面刷新问题**. [#441](https://github.com/crawlab-team/crawlab/issues/441) - **结果不支持 JSON**. [#202](https://github.com/crawlab-team/crawlab/issues/202) - **修复“删除爬虫后获取所有爬虫”错误**. - **修复 i18n 警告**. # 0.4.4 (2020-01-17) ### 功能 / 优化 - **邮件通知**. 允许用户发送邮件消息通知. - **钉钉机器人通知**. 允许用户发送钉钉机器人消息通知. - **企业微信机器人通知**. 允许用户发送企业微信机器人消息通知. - **API 地址优化**. 在前端加入相对路径,因此用户不需要特别注明 `CRAWLAB_API_ADDRESS`. - **SDK 兼容**. 允许用户通过 Crawlab SDK 与 Scrapy 或通用爬虫集成. - **优化文件管理**. 加入树状文件侧边栏,让用户更方便的编辑文件. - **高级定时任务 Cron**. 允许用户通过 Cron 可视化编辑器编辑定时任务. ### Bug 修复 - **`nil retuened` 错误**. - **使用 HTTPS 出现的报错**. - **无法在爬虫列表页运行可配置爬虫**. - **上传爬虫文件缺少表单验证**. # 0.4.3 (2020-01-07) ### 功能 / 优化 - **依赖安装**. 允许用户在平台 Web 界面安装/卸载依赖以及添加编程语言(暂时只有 Node.js)。 - **Docker 中预装编程语言**. 允许 Docker 用户通过设置 `CRAWLAB_SERVER_LANG_NODE` 为 `Y` 来预装 `Node.js` 环境. - **在爬虫详情页添加定时任务列表**. 允许用户在爬虫详情页查看、添加、编辑定时任务. [#360](https://github.com/crawlab-team/crawlab/issues/360) - **Cron 表达式与 Linux 一致**. 将表达式从 6 元素改为 5 元素,与 Linux 一致. - **启用/禁用定时任务**. 允许用户启用/禁用定时任务. [#297](https://github.com/crawlab-team/crawlab/issues/297) - **优化任务管理**. 允许用户批量删除任务. [#341](https://github.com/crawlab-team/crawlab/issues/341) - **优化爬虫管理**. 允许用户在爬虫列表页对爬虫进行筛选和排序. - **添加中文版 `CHANGELOG`**. - **在顶部添加 Github 加星按钮**. ### Bug 修复 - **定时任务问题**. [#423](https://github.com/crawlab-team/crawlab/issues/423) - **上传爬虫zip文件问题**. [#403](https://github.com/crawlab-team/crawlab/issues/403) [#407](https://github.com/crawlab-team/crawlab/issues/407) - **因为网络原因导致崩溃**. [#340](https://github.com/crawlab-team/crawlab/issues/340) - **定时任务无法正常运行** - **定时任务列表列表错位问题** - **刷新按钮跳转错误问题** # 0.4.2 (2019-12-26) ### 功能 / 优化 - **免责声明**. 加入免责声明. - **通过 API 获取版本号**. [#371](https://github.com/crawlab-team/crawlab/issues/371) - **通过配置来允许用户注册**. [#346](https://github.com/crawlab-team/crawlab/issues/346) - **允许添加新用户**. - **更高级的文件管理**. 允许用户添加、编辑、重命名、删除代码文件. [#286](https://github.com/crawlab-team/crawlab/issues/286) - **优化爬虫创建流程**. 允许用户在上传 zip 文件前创建空的自定义爬虫. - **优化任务管理**. 允许用户通过选择条件过滤任务. [#341](https://github.com/crawlab-team/crawlab/issues/341) ### Bug 修复 - **重复节点**. [#391](https://github.com/crawlab-team/crawlab/issues/391) - **"mongodb no reachable" 错误**. [#373](https://github.com/crawlab-team/crawlab/issues/373) # 0.4.1 (2019-12-13) ### 功能 / 优化 - **Spiderfile 优化**. 将阶段由数组更换为字典. [#358](https://github.com/crawlab-team/crawlab/issues/358) - **百度统计更新**. ### Bug 修复 - **无法展示定时任务**. [#353](https://github.com/crawlab-team/crawlab/issues/353) - **重复节点注册**. [#334](https://github.com/crawlab-team/crawlab/issues/334) # 0.4.0 (2019-12-06) ### 功能 / 优化 - **可配置爬虫**. 允许用户添加 `Spiderfile` 来配置抓取规则. - **执行模式**. 允许用户选择 3 种任务执行模式: *所有节点*, *指定节点* and *随机*. ### Bug 修复 - **任务意外被杀死**. [#306](https://github.com/crawlab-team/crawlab/issues/306) - **文档更正**. [#301](https://github.com/crawlab-team/crawlab/issues/258) [#301](https://github.com/crawlab-team/crawlab/issues/258) - **直接部署与 Windows 不兼容**. [#288](https://github.com/crawlab-team/crawlab/issues/288) - **日志文件丢失**. [#269](https://github.com/crawlab-team/crawlab/issues/269) # 0.3.5 (2019-10-28) ### 功能 / 优化 - **优雅关闭**. [详情](https://github.com/crawlab-team/crawlab/commit/63fab3917b5a29fd9770f9f51f1572b9f0420385) - **节点信息优化**. [详情](https://github.com/crawlab-team/crawlab/commit/973251a0fbe7a2184ac0da09e0404a17c736aee7) - **将系统环境变量添加到任务**. [详情](https://github.com/crawlab-team/crawlab/commit/4ab4892471965d6342d30385578ca60dc51f8ad3) - **自动刷新任务日志**. [详情](https://github.com/crawlab-team/crawlab/commit/4ab4892471965d6342d30385578ca60dc51f8ad3) - **允许 HTTPS 部署**. [详情](https://github.com/crawlab-team/crawlab/commit/5d8f6f0c56768a6e58f5e46cbf5adff8c7819228) ### Bug 修复 - **定时任务中无法获取爬虫列表**. [详情](https://github.com/crawlab-team/crawlab/commit/311f72da19094e3fa05ab4af49812f58843d8d93) - **无法获取工作节点信息**. [详情](https://github.com/crawlab-team/crawlab/commit/6af06efc17685a9e232e8c2b5fd819ec7d2d1674) - **运行爬虫任务时无法选择节点**. [详情](https://github.com/crawlab-team/crawlab/commit/31f8e03234426e97aed9b0bce6a50562f957edad) - **结果量很大时无法获取结果数量**. [#260](https://github.com/crawlab-team/crawlab/issues/260) - **定时任务中的节点问题**. [#244](https://github.com/crawlab-team/crawlab/issues/244) # 0.3.1 (2019-08-25) ### 功能 / 优化 - **Docker 镜像优化**. 将 Docker 镜像进一步分割成 alpine 镜像版本的 master、worker、frontendSplit docker further into master, worker, frontend. - **单元测试**. 用单元测试覆盖部分后端代码. - **前端优化**. 登录页、按钮大小、上传 UI 提示. - **更灵活的节点注册**. 允许用户传一个变量作为注册 key,而不是默认的 MAC 地址. ### Bug 修复 - **上传大爬虫文件错误**. 上传大爬虫文件时的内存崩溃问题. [#150](https://github.com/crawlab-team/crawlab/issues/150) - **无法同步爬虫**. 通过提高写权限等级来修复同步爬虫文件时的问题. [#114](https://github.com/crawlab-team/crawlab/issues/114) - **爬虫页问题**. 通过删除 `Site` 字段来修复. [#112](https://github.com/crawlab-team/crawlab/issues/112) - **节点展示问题**. 当在多个机器上跑 Docker 容器时,节点无法正确展示. [#99](https://github.com/crawlab-team/crawlab/issues/99) # 0.3.0 (2019-07-31) ### 功能 / 优化 - **Golang 后端**: 将后端由 Python 重构为 Golang,很大的提高了稳定性和性能. - **节点网络图**: 节点拓扑图可视化. - **节点系统信息**: 可以查看包括操作系统、CPU数量、可执行文件在内的系统信息. - **节点监控改进**: 节点通过 Redis 来监控和注册. - **文件管理**: 可以在线编辑爬虫文件,包括代码高亮. - **登录页/注册页/用户管理**: 要求用户登录后才能使用 Crawlab, 允许用户注册和用户管理,有一些基于角色的鉴权机制. - **自动部署爬虫**: 爬虫将被自动部署或同步到所有在线节点. - **更小的 Docker 镜像**: 瘦身版 Docker 镜像,通过多阶段构建将 Docker 镜像大小从 1.3G 减小到 700M 左右. ### Bug 修复 - **节点状态**. 节点状态不会随着节点下线而更新. [#87](https://github.com/tikazyq/crawlab/issues/87) - **爬虫部署错误**. 通过自动爬虫部署来修复 [#83](https://github.com/tikazyq/crawlab/issues/83) - **节点无法显示**. 节点无法显示在线 [#81](https://github.com/tikazyq/crawlab/issues/81) - **定时任务无法工作**. 通过 Golang 后端修复 [#64](https://github.com/tikazyq/crawlab/issues/64) - **Flower 错误**. 通过 Golang 后端修复 [#57](https://github.com/tikazyq/crawlab/issues/57) # 0.2.4 (2019-07-07) ### 功能 / 优化 - **文档**: 更优和更详细的文档. - **更好的 Crontab**: 通过 UI 界面生成 Cron 表达式. - **更优的性能**: 从原生 flask 引擎 切换到 `gunicorn`. [#78](https://github.com/tikazyq/crawlab/issues/78) ### Bug 修复 - **删除爬虫**. 删除爬虫时不止在数据库中删除,还应该删除相关的文件夹、任务和定时任务. [#69](https://github.com/tikazyq/crawlab/issues/69) - **MongoDB 授权**. 允许用户注明 `authenticationDatabase` 来连接 `mongodb`. [#68](https://github.com/tikazyq/crawlab/issues/68) - **Windows 兼容性**. 加入 `eventlet` 到 `requirements.txt`. [#59](https://github.com/tikazyq/crawlab/issues/59) # 0.2.3 (2019-06-12) ### 功能 / 优化 - **Docker**: 用户能够运行 Docker 镜像来加快部署. - **CLI**: 允许用户通过命令行来执行 Crawlab 程序. - **上传爬虫**: 允许用户上传自定义爬虫到 Crawlab. - **预览时编辑字段**: 允许用户在可配置爬虫中预览数据时编辑字段. ### Bug 修复 - **爬虫分页**. 爬虫列表页中修复分页问题. # 0.2.2 (2019-05-30) ### 功能 / 优化 - **自动抓取字段**: 在可配置爬虫列表页种自动抓取字段. - **下载结果**: 允许下载结果为 CSV 文件. - **百度统计**: 允许用户选择是否允许向百度统计发送统计数据. ### Bug 修复 - **结果页分页**. [#45](https://github.com/tikazyq/crawlab/issues/45) - **定时任务重复触发**: 将 Flask DEBUG 设置为 False 来保证定时任务无法重复触发. [#32](https://github.com/tikazyq/crawlab/issues/32) - **前端环境**: 添加 `VUE_APP_BASE_URL` 作为生产环境模式变量,然后 API 不会永远都是 `localhost` [#30](https://github.com/tikazyq/crawlab/issues/30) # 0.2.1 (2019-05-27) - **可配置爬虫**: 允许用户创建爬虫来抓取数据,而不用编写代码. # 0.2 (2019-05-10) - **高级数据统计**: 爬虫详情页的高级数据统计. - **网站数据**: 加入网站列表(中国),允许用户查看 robots.txt、首页响应时间等信息. # 0.1.1 (2019-04-23) - **基础统计**: 用户可以查看基础统计数据,包括爬虫和任务页中的失败任务数、结果数. - **近实时任务信息**: 周期性(5 秒)向服务器轮训数据来实现近实时查看任务信息. - **定时任务**: 利用 apscheduler 实现定时任务,允许用户设置类似 Cron 的定时任务. # 0.1 (2019-04-17) - **首次发布** ================================================ FILE: CHANGELOG.md ================================================ # 0.6.0 (TBC) (TBC) # 0.5.1 (2020-07-31) ### Features / Enhancement - **Added error message details**. - **Added Golang programming language support**. - **Added web driver installation scripts for Chrome Driver and Firefox**. - **Support system tasks**. A "system task" is similar to normal spider task, it allows users to view logs of general tasks such as installing languages. - **Changed methods of installing languages from RPC to system tasks**. ### Bug Fixes - **Fixed first download repo 500 error in Spider Market page**. [#808](https://github.com/crawlab-team/crawlab/issues/808) - **Fixed some translation issues**. - **Fixed 500 error in task detail page**. [#810](https://github.com/crawlab-team/crawlab/issues/810) - **Fixed password reset issue**. [#811](https://github.com/crawlab-team/crawlab/issues/811) - **Fixed unable to download CSV issue**. [#812](https://github.com/crawlab-team/crawlab/issues/812) - **Fixed unable to install node.js issue**. [#813](https://github.com/crawlab-team/crawlab/issues/813) - **Fixed disabled status for batch adding schedules**. [#814](https://github.com/crawlab-team/crawlab/issues/814) # 0.5.0 (2020-07-19) ### Features / Enhancement - **Spider Market**. Allow users to download open-source spiders into Crawlab. - **Batch actions**. Allow users to interact with Crawlab in batch fashions, e.g. batch run tasks, batch delete spiders, ect. - **Migrate MongoDB driver to `MongoDriver`**. - **Refactor and optmize node-related logics**. - **Change default `task.workers` to 16**. - **Change default nginx `client_max_body_size` to 200m**. - **Support writing logs to ElasticSearch**. - **Display error details in Scrapy page**. - **Removed Challenge page**. - **Moved Feedback and Dislaimer pages to navbar**. ### Bug Fixes - **Fixed log not expiring issue because of failure to create TTL index**. - **Set default log expire duration to 1 day**. - **`task_id` index not created**. - **`docker-compose.yml` fix**. - **Fixed 404 page**. - **Fixed unable to create worker node before master node issue**. # 0.4.10 (2020-04-21) ### Features / Enhancement - **Enhanced Log Management**. Centralizing log storage in MongoDB, reduced the dependency of PubSub, allowing log error detection. - **API Token**. Allow users to generate API tokens and use them to integrate into their own systems. - **Web Hook**. Trigger a Web Hook http request to pre-defined URL when a task starts or finishes. - **Auto Install Dependencies**. Allow installing dependencies automatically from `requirements.txt` or `package.json`. - **Auto Results Collection**. Set results collection to `results_` if it is not set. - **Optimized Project List**. Not display "No Project" item in the project list. - **Upgrade Node.js**. Upgrade Node.js version from v8.12 to v10.19. - **Add Run Button in Schedule Page**. Allow users to manually run task in Schedule Page. ### Bug Fixes - **Cannot register**. [#670](https://github.com/crawlab-team/crawlab/issues/670) - **Spider schedule tab cron expression shows second**. [#678](https://github.com/crawlab-team/crawlab/issues/678) - **Missing daily stats in spider**. [#684](https://github.com/crawlab-team/crawlab/issues/684) - **Results count not update in time**. [#689](https://github.com/crawlab-team/crawlab/issues/689) # 0.4.9 (2020-03-31) ### Features / Enhancement - **Challenges**. Users can achieve different challenges based on their actions. - **More Advanced Access Control**. More granular access control, e.g. normal users can only view/manage their own spiders/projects and admin users can view/manage all spiders/projects. - **Feedback**. Allow users to send feedbacks and ratings to Crawlab team. - **Better Home Page Metrics**. Optimized metrics display on home page. - **Configurable Spiders Converted to Customized Spiders**. Allow users to convert their configurable spiders into customized spiders which are also Scrapy spiders. - **View Tasks Triggered by Schedule**. Allow users to view tasks triggered by a schedule. [#648](https://github.com/crawlab-team/crawlab/issues/648) - **Support Results De-Duplication**. Allow users to configure de-duplication of results. [#579](https://github.com/crawlab-team/crawlab/issues/579) - **Support Task Restart**. Allow users to re-run historical tasks. ### Bug Fixes - **CLI unable to use on Windows**. [#580](https://github.com/crawlab-team/crawlab/issues/580) - **Re-upload error**. [#643](https://github.com/crawlab-team/crawlab/issues/643) [#640](https://github.com/crawlab-team/crawlab/issues/640) - **Upload missing folders**. [#646](https://github.com/crawlab-team/crawlab/issues/646) - **Unable to add schedules in Spider Page**. # 0.4.8 (2020-03-11) ### Features / Enhancement - **Support Installations of More Programming Languages**. Now users can install or pre-install more programming languages including Java, .Net Core and PHP. - **Installation UI Optimization**. Users can better view and manage installations on Node List page. - **More Git Support**. Allow users to view Git Commits record, and allow checkout to corresponding commit. - **Support Hostname Node Registration Type**. Users can set hostname as the node key as the unique identifier. - **RPC Support**. Added RPC support to better manage node communication. - **Run On Master Switch**. Users can determine whether to run tasks on master. If not, all tasks will be run only on worker nodes. - **Disabled Tutorial by Default**. - **Added Related Documentation Sidebar**. - **Loading Page Optimization**. ### Bug Fixes - **Duplicated Nodes**. [#391](https://github.com/crawlab-team/crawlab/issues/391) - **Duplicated Spider Upload**. [#603](https://github.com/crawlab-team/crawlab/issues/603) - **Failure in dependencies installation results in unusable dependency installation functionalities.**. [#609](https://github.com/crawlab-team/crawlab/issues/609) - **Create Tasks for Offline Nodes**. [#622](https://github.com/crawlab-team/crawlab/issues/622) # 0.4.7 (2020-02-24) ### Features / Enhancement - **Better Support for Scrapy**. Spiders identification, `settings.py` configuration, log level selection, spider selection. [#435](https://github.com/crawlab-team/crawlab/issues/435) - **Git Sync**. Allow users to sync git projects to Crawlab. - **Long Task Support**. Users can add long-task spiders which is supposed to run without finishing. [#425](https://github.com/crawlab-team/crawlab/issues/425) - **Spider List Optimization**. Tasks count by status, tasks detail popup, legend. [#425](https://github.com/crawlab-team/crawlab/issues/425) - **Upgrade Check**. Check latest version and notifiy users to upgrade. - **Spiders Batch Operation**. Allow users to run/stop spider tasks and delete spiders in batches. - **Copy Spiders**. Allow users to copy an existing spider to create a new one. - **Wechat Group QR Code**. ### Bug Fixes - **Schedule Spider Selection Issue**. Fields not responding to spider change. - **Cron Jobs Conflict**. Possible bug when two spiders set to the same time of their cron jobs. [#515](https://github.com/crawlab-team/crawlab/issues/515) [#565](https://github.com/crawlab-team/crawlab/issues/565) - **Task Log Issue**. Different tasks write to the same log file if triggered at the same time. [#577](https://github.com/crawlab-team/crawlab/issues/577) - **Task List Filter Options Incomplete**. # 0.4.6 (2020-02-13) ### Features / Enhancement - **SDK for Node.js**. Users can apply SDK in their Node.js spiders. - **Log Management Optimization**. Log search, error highlight, auto-scrolling. - **Task Execution Process Optimization**. Allow users to be redirected to task detail page after triggering a task. - **Task Display Optimization**. Added "Param" in the Latest Tasks table in the spider detail page. [#295](https://github.com/crawlab-team/crawlab/issues/295) - **Spider List Optimization**. Added "Update Time" and "Create Time" in spider list page. - **Page Loading Placeholder**. ### Bug Fixes - **Lost Focus in Schedule Configuration**. [#519](https://github.com/crawlab-team/crawlab/issues/519) - **Unable to Upload Spider using CLI**. [#524](https://github.com/crawlab-team/crawlab/issues/524) # 0.4.5 (2020-02-03) ### Features / Enhancement - **Interactive Tutorial**. Guide users through the main functionalities of Crawlab. - **Global Environment Variables**. Allow users to set global environment variables, which will be passed into all spider programs. [#177](https://github.com/crawlab-team/crawlab/issues/177) - **Project**. Allow users to link spiders to projects. [#316](https://github.com/crawlab-team/crawlab/issues/316) - **Demo Spiders**. Added demo spiders when Crawlab is initialized. [#379](https://github.com/crawlab-team/crawlab/issues/379) - **User Admin Optimization**. Restrict privilleges of admin users. [#456](https://github.com/crawlab-team/crawlab/issues/456) - **Setting Page Optimization**. - **Task Results Optimization**. ### Bug Fixes - **Unable to find spider file error**. [#485](https://github.com/crawlab-team/crawlab/issues/485) - **Click delete button results in redirect**. [#480](https://github.com/crawlab-team/crawlab/issues/480) - **Unable to create files in an empty spider**. [#479](https://github.com/crawlab-team/crawlab/issues/479) - **Download results error**. [#465](https://github.com/crawlab-team/crawlab/issues/465) - **crawlab-sdk CLI error**. [#458](https://github.com/crawlab-team/crawlab/issues/458) - **Page refresh issue**. [#441](https://github.com/crawlab-team/crawlab/issues/441) - **Results not support JSON**. [#202](https://github.com/crawlab-team/crawlab/issues/202) - **Getting all spider after deleting a spider**. - **i18n warning**. # 0.4.4 (2020-01-17) ### Features / Enhancement - **Email Notification**. Allow users to send email notifications. - **DingTalk Robot Notification**. Allow users to send DingTalk Robot notifications. - **Wechat Robot Notification**. Allow users to send Wechat Robot notifications. - **API Address Optimization**. Added relative URL path in frontend so that users don't have to specify `CRAWLAB_API_ADDRESS` explicitly. - **SDK Compatiblity**. Allow users to integrate Scrapy or general spiders with Crawlab SDK. - **Enhanced File Management**. Added tree-like file sidebar to allow users to edit files much more easier. - **Advanced Schedule Cron**. Allow users to edit schedule cron with visualized cron editor. ### Bug Fixes - **`nil retuened` error**. - **Error when using HTTPS**. - **Unable to run Configurable Spiders on Spider List**. - **Missing form validation before uploading spider files**. # 0.4.3 (2020-01-07) ### Features / Enhancement - **Dependency Installation**. Allow users to install/uninstall dependencies and add programming languages (Node.js only for now) on the platform web interface. - **Pre-install Programming Languages in Docker**. Allow Docker users to set `CRAWLAB_SERVER_LANG_NODE` as `Y` to pre-install `Node.js` environments. - **Add Schedule List in Spider Detail Page**. Allow users to view / add / edit schedule cron jobs in the spider detail page. [#360](https://github.com/crawlab-team/crawlab/issues/360) - **Align Cron Expression with Linux**. Change the expression of 6 elements to 5 elements as aligned in Linux. - **Enable/Disable Schedule Cron**. Allow users to enable/disable the schedule jobs. [#297](https://github.com/crawlab-team/crawlab/issues/297) - **Better Task Management**. Allow users to batch delete tasks. [#341](https://github.com/crawlab-team/crawlab/issues/341) - **Better Spider Management**. Allow users to sort and filter spiders in the spider list page. - **Added Chinese `CHANGELOG`**. - **Added Github Star Button at Nav Bar**. ### Bug Fixes - **Schedule Cron Task Issue**. [#423](https://github.com/crawlab-team/crawlab/issues/423) - **Upload Spider Zip File Issue**. [#403](https://github.com/crawlab-team/crawlab/issues/403) [#407](https://github.com/crawlab-team/crawlab/issues/407) - **Exit due to Network Failure**. [#340](https://github.com/crawlab-team/crawlab/issues/340) - **Cron Jobs not Running Correctly** - **Schedule List Columns Mis-positioned** - **Clicking Refresh Button Redirected to 404 Page** # 0.4.2 (2019-12-26) ### Features / Enhancement - **Disclaimer**. Added page for Disclaimer. - **Call API to fetch version**. [#371](https://github.com/crawlab-team/crawlab/issues/371) - **Configure to allow user registration**. [#346](https://github.com/crawlab-team/crawlab/issues/346) - **Allow adding new users**. - **More Advanced File Management**. Allow users to add / edit / rename / delete files. [#286](https://github.com/crawlab-team/crawlab/issues/286) - **Optimized Spider Creation Process**. Allow users to create an empty customized spider before uploading the zip file. - **Better Task Management**. Allow users to filter tasks by selecting through certian criterions. [#341](https://github.com/crawlab-team/crawlab/issues/341) ### Bug Fixes - **Duplicated nodes**. [#391](https://github.com/crawlab-team/crawlab/issues/391) - **"mongodb no reachable" error**. [#373](https://github.com/crawlab-team/crawlab/issues/373) # 0.4.1 (2019-12-13) ### Features / Enhancement - **Spiderfile Optimization**. Stages changed from dictionary to array. [#358](https://github.com/crawlab-team/crawlab/issues/358) - **Baidu Tongji Update**. ### Bug Fixes - **Unable to display schedule tasks**. [#353](https://github.com/crawlab-team/crawlab/issues/353) - **Duplicate node registration**. [#334](https://github.com/crawlab-team/crawlab/issues/334) # 0.4.0 (2019-12-06) ### Features / Enhancement - **Configurable Spider**. Allow users to add spiders using *Spiderfile* to configure crawling rules. - **Execution Mode**. Allow users to select 3 modes for task execution: *All Nodes*, *Selected Nodes* and *Random*. ### Bug Fixes - **Task accidentally killed**. [#306](https://github.com/crawlab-team/crawlab/issues/306) - **Documentation fix**. [#301](https://github.com/crawlab-team/crawlab/issues/258) [#301](https://github.com/crawlab-team/crawlab/issues/258) - **Direct deploy incompatible with Windows**. [#288](https://github.com/crawlab-team/crawlab/issues/288) - **Log files lost**. [#269](https://github.com/crawlab-team/crawlab/issues/269) # 0.3.5 (2019-10-28) ### Features / Enhancement - **Graceful Showdown**. [detail](https://github.com/crawlab-team/crawlab/commit/63fab3917b5a29fd9770f9f51f1572b9f0420385) - **Node Info Optimization**. [detail](https://github.com/crawlab-team/crawlab/commit/973251a0fbe7a2184ac0da09e0404a17c736aee7) - **Append System Environment Variables to Tasks**. [detail](https://github.com/crawlab-team/crawlab/commit/4ab4892471965d6342d30385578ca60dc51f8ad3) - **Auto Refresh Task Log**. [detail](https://github.com/crawlab-team/crawlab/commit/4ab4892471965d6342d30385578ca60dc51f8ad3) - **Enable HTTPS Deployment**. [detail](https://github.com/crawlab-team/crawlab/commit/5d8f6f0c56768a6e58f5e46cbf5adff8c7819228) ### Bug Fixes - **Unable to fetch spider list info in schedule jobs**. [detail](https://github.com/crawlab-team/crawlab/commit/311f72da19094e3fa05ab4af49812f58843d8d93) - **Unable to fetch node info from worker nodes**. [detail](https://github.com/crawlab-team/crawlab/commit/6af06efc17685a9e232e8c2b5fd819ec7d2d1674) - **Unable to select node when trying to run spider tasks**. [detail](https://github.com/crawlab-team/crawlab/commit/31f8e03234426e97aed9b0bce6a50562f957edad) - **Unable to fetch result count when result volume is large**. [#260](https://github.com/crawlab-team/crawlab/issues/260) - **Node issue in schedule tasks**. [#244](https://github.com/crawlab-team/crawlab/issues/244) # 0.3.1 (2019-08-25) ### Features / Enhancement - **Docker Image Optimization**. Split docker further into master, worker, frontend with alpine image. - **Unit Tests**. Covered part of the backend code with unit tests. - **Frontend Optimization**. Login page, button size, hints of upload UI optimization. - **More Flexible Node Registration**. Allow users to pass a variable as key for node registration instead of MAC by default. ### Bug Fixes - **Uploading Large Spider Files Error**. Memory crash issue when uploading large spider files. [#150](https://github.com/crawlab-team/crawlab/issues/150) - **Unable to Sync Spiders**. Fixes through increasing level of write permission when synchronizing spider files. [#114](https://github.com/crawlab-team/crawlab/issues/114) - **Spider Page Issue**. Fixes through removing the field "Site". [#112](https://github.com/crawlab-team/crawlab/issues/112) - **Node Display Issue**. Nodes do not display correctly when running docker containers on multiple machines. [#99](https://github.com/crawlab-team/crawlab/issues/99) # 0.3.0 (2019-07-31) ### Features / Enhancement - **Golang Backend**: Refactored code from Python backend to Golang, much more stability and performance. - **Node Network Graph**: Visualization of node typology. - **Node System Info**: Available to see system info including OS, CPUs and executables. - **Node Monitoring Enhancement**: Nodes are monitored and registered through Redis. - **File Management**: Available to edit spider files online, including code highlight. - **Login/Regiser/User Management**: Require users to login to use Crawlab, allow user registration and user management, some role-based authorization. - **Automatic Spider Deployment**: Spiders are deployed/synchronized to all online nodes automatically. - **Smaller Docker Image**: Slimmed Docker image and reduced Docker image size from 1.3G to \~700M by applying Multi-Stage Build. ### Bug Fixes - **Node Status**. Node status does not change even though it goes offline actually. [#87](https://github.com/tikazyq/crawlab/issues/87) - **Spider Deployment Error**. Fixed through Automatic Spider Deployment [#83](https://github.com/tikazyq/crawlab/issues/83) - **Node not showing**. Node not able to show online [#81](https://github.com/tikazyq/crawlab/issues/81) - **Cron Job not working**. Fixed through new Golang backend [#64](https://github.com/tikazyq/crawlab/issues/64) - **Flower Error**. Fixed through new Golang backend [#57](https://github.com/tikazyq/crawlab/issues/57) # 0.2.4 (2019-07-07) ### Features / Enhancement - **Documentation**: Better and much more detailed documentation. - **Better Crontab**: Make crontab expression through crontab UI. - **Better Performance**: Switched from native flask engine to `gunicorn`. [#78](https://github.com/tikazyq/crawlab/issues/78) ### Bugs Fixes - **Deleting Spider**. Deleting a spider does not only remove record in db but also removing related folder, tasks and schedules. [#69](https://github.com/tikazyq/crawlab/issues/69) - **MongoDB Auth**. Allow user to specify `authenticationDatabase` to connect to `mongodb`. [#68](https://github.com/tikazyq/crawlab/issues/68) - **Windows Compatibility**. Added `eventlet` to `requirements.txt`. [#59](https://github.com/tikazyq/crawlab/issues/59) # 0.2.3 (2019-06-12) ### Features / Enhancement - **Docker**: User can run docker image to speed up deployment. - **CLI**: Allow user to use command-line interface to execute Crawlab programs. - **Upload Spider**: Allow user to upload Customized Spider to Crawlab. - **Edit Fields on Preview**: Allow user to edit fields when previewing data in Configurable Spider. ### Bugs Fixes - **Spiders Pagination**. Fixed pagination problem in spider page. # 0.2.2 (2019-05-30) ### Features / Enhancement - **Automatic Extract Fields**: Automatically extracting data fields in list pages for configurable spider. - **Download Results**: Allow downloading results as csv file. - **Baidu Tongji**: Allow users to choose to report usage info to Baidu Tongji. ### Bug Fixes - **Results Page Pagination**: Fixes so the pagination of results page is working correctly. [#45](https://github.com/tikazyq/crawlab/issues/45) - **Schedule Tasks Duplicated Triggers**: Set Flask DEBUG as False so that schedule tasks won't trigger twice. [#32](https://github.com/tikazyq/crawlab/issues/32) - **Frontend Environment**: Added `VUE_APP_BASE_URL` as production mode environment variable so the API call won't be always `localhost` in deployed env [#30](https://github.com/tikazyq/crawlab/issues/30) # 0.2.1 (2019-05-27) - **Configurable Spider**: Allow users to create a spider to crawl data without coding. # 0.2 (2019-05-10) - **Advanced Stats**: Advanced analytics in spider detail view. - **Sites Data**: Added sites list (China) for users to check info such as robots.txt and home page response time/code. # 0.1.1 (2019-04-23) - **Basic Stats**: User can view basic stats such as number of failed tasks and number of results in spiders and tasks pages. - **Near Realtime Task Info**: Periodically (5 sec) polling data from server to allow view task info in a near-realtime fashion. - **Scheduled Tasks**: Allow users to set up cron-like scheduled/periodical tasks using apscheduler. # 0.1 (2019-04-17) - **Initial Release** ================================================ FILE: DISCLAIMER-zh.md ================================================ # 免责声明 本免责及隐私保护声明(以下简称“免责声明”或“本声明”)适用于 Crawlab 开发组 (以下简称“开发组”)研发的系列软件(以下简称"Crawlab") 在您阅读本声明后若不同意此声明中的任何条款,或对本声明存在质疑,请立刻停止使用我们的软件。若您已经开始或正在使用 Crawlab,则表示您已阅读并同意本声明的所有条款之约定。 1. 总则:您通过安装 Crawlab 并使用 Crawlab 提供的服务与功能即表示您已经同意与开发组立本协议。开发组可随时执行全权决定更改“条款”。经修订的“条款”一经在 Github 免责声明页面上公布后,立即自动生效。 2. 本产品是基于Golang的分布式爬虫管理平台,支持Python、NodeJS、Go、Java、PHP等多种编程语言以及多种爬虫框架。 3. 一切因使用 Crawlab 而引致之任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其所造成的损失(包括在非官方站点下载 Crawlab 而感染电脑病毒),Crawlab 开发组概不负责,亦不承担任何法律责任。 4. 用户对使用 Crawlab 自行承担风险,我们不做任何形式的保证, 因网络状况、通讯线路等任何技术原因而导致用户不能正常升级更新,我们也不承担任何法律责任。 5. 用户使用 Crawlab 对目标网站进行抓取时需遵从《网络安全法》等与爬虫相关的法律法规,切勿擅自采集公民个人信息、用 DDoS 等方式造成目标网站瘫痪、不遵从目标网站的 robots.txt 协议等非法手段。 6. Crawlab 尊重并保护所有用户的个人隐私权,不会窃取任何用户计算机中的信息。 7. 系统的版权:Crawlab 开发组对所有开发的或合作开发的产品拥有知识产权,著作权,版权和使用权,这些产品受到适用的知识产权、版权、商标、服务商标、专利或其他法律的保护。 8. 传播:任何公司或个人在网络上发布,传播我们软件的行为都是允许的,但因公司或个人传播软件可能造成的任何法律和刑事事件 Crawlab 开发组不负任何责任。 ================================================ FILE: DISCLAIMER.md ================================================ # Disclaimer This Disclaimer and privacy protection statement (hereinafter referred to as "disclaimer statement" or "this statement") is applicable to the series of software (hereinafter referred to as "crawlab") developed by crawlab development group (hereinafter referred to as "development group") after you read this statement, if you do not agree with any terms in this statement or have doubts about this statement, please stop using our software immediately. If you have started or are using crawlab, you have read and agree to all terms of this statement. 1. General: by installing crawlab and using the services and functions provided by crawlab, you have agreed to establish this agreement with the development team. The developer group may at any time change the terms at its sole discretion. The amended "terms" shall take effect automatically as soon as they are published on the GitHub disclaimer page. 2. This product is a distributed crawler management platform based on golang, supporting python, nodejs, go, Java, PHP and other programming languages as well as a variety of crawler frameworks. 3. The development team of crawlab shall not be responsible for any accident, negligence, contract damage, defamation, copyright or intellectual property infringement caused by the use of crawlab and any loss caused by it (including computer virus infection caused by downloading crawlab on the unofficial site), and shall not bear any legal responsibility. 4. The user shall bear the risk of using crawlab by himself, we do not make any form of guarantee, and we will not bear any legal responsibility for the user's failure to upgrade and update normally due to any technical reasons such as network condition and communication line. 5. When users use crawlab to grab the target website, they need to comply with the laws and regulations related to crawlers, such as the network security law. Do not collect personal information of citizens without authorization, cause the target website to be paralyzed by DDoS, or fail to comply with the robots.txt protocol and other illegal means of the target website. 6. Crawlab respects and protects the personal privacy of all users and will not steal any information from users' computers. 7. Copyright of the system: Crawlab development team owns the intellectual property rights, copyrights, copyrights and use rights for all developed or jointly developed products, which are protected by applicable intellectual property rights, copyrights, trademarks, service trademarks, patents or other laws. 8. Communication: any company or individual who publishes or disseminates our software on the Internet is allowed, but the crawlab development team shall not be responsible for any legal and criminal events that may be caused by the company or individual disseminating the software. ================================================ FILE: Dockerfile ================================================ FROM crawlabteam/crawlab-backend:latest AS backend-build FROM crawlabteam/crawlab-frontend:latest AS frontend-build FROM crawlabteam/crawlab-public-plugins:latest AS public-plugins-build # images FROM crawlabteam/crawlab-base:latest # add files COPY ./backend/conf /app/backend/conf COPY ./nginx /app/nginx COPY ./bin /app/bin # copy backend files RUN mkdir -p /opt/bin COPY --from=backend-build /go/bin/crawlab /opt/bin RUN cp /opt/bin/crawlab /usr/local/bin/crawlab-server # copy frontend files COPY --from=frontend-build /app/dist /app/dist # copy public-plugins files COPY --from=public-plugins-build /app/plugins /app/plugins # copy nginx config files COPY ./nginx/crawlab.conf /etc/nginx/conf.d # start backend CMD ["/bin/bash", "/app/bin/docker-init.sh"] ================================================ FILE: LICENSE ================================================ BSD 3-Clause License Copyright (c) 2020, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: README-zh.md ================================================ # Crawlab

中文 | [English](https://github.com/crawlab-team/crawlab) [安装](#安装) | [运行](#运行) | [截图](#截图) | [架构](#架构) | [集成](#与其他框架的集成) | [比较](#与其他框架比较) | [相关文章](#相关文章) | [社区&赞助](#社区--赞助) | [更新日志](https://github.com/crawlab-team/crawlab/blob/main/CHANGELOG-zh.md) | [免责声明](https://github.com/crawlab-team/crawlab/blob/main/DISCLAIMER-zh.md) 基于Golang的分布式爬虫管理平台,支持Python、NodeJS、Go、Java、PHP等多种编程语言以及多种爬虫框架。 [查看演示 Demo](https://demo.crawlab.cn) | [文档](https://docs.crawlab.cn/zh/) ## 安装 您可以参考这个[安装指南](https://docs.crawlab.cn/zh/guide/installation)。 ## 快速开始 请打开命令行并执行下列命令。请保证您已经提前安装了 `docker-compose`。 ```bash git clone https://github.com/crawlab-team/examples cd examples/docker/basic docker-compose up -d ``` 接下来,您可以看看 `docker-compose.yml` (包含详细配置参数),以及参考 [文档](http://docs.crawlab.cn) 来查看更多信息。 ## 运行 ### Docker 请用`docker-compose`来一键启动,甚至不用配置 MongoDB 数据库,**当然我们推荐这样做**。在当前目录中创建`docker-compose.yml`文件,输入以下内容。 ```yaml version: '3.3' services: master: image: crawlabteam/crawlab:latest container_name: crawlab_example_master environment: CRAWLAB_NODE_MASTER: "Y" CRAWLAB_MONGO_HOST: "mongo" volumes: - "./.crawlab/master:/root/.crawlab" ports: - "8080:8080" depends_on: - mongo worker01: image: crawlabteam/crawlab:latest container_name: crawlab_example_worker01 environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" volumes: - "./.crawlab/worker01:/root/.crawlab" depends_on: - master worker02: image: crawlabteam/crawlab:latest container_name: crawlab_example_worker02 environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" volumes: - "./.crawlab/worker02:/root/.crawlab" depends_on: - master mongo: image: mongo:4.2 container_name: crawlab_example_mongo restart: always ``` 然后执行以下命令,Crawlab主节点、工作节点+MongoDB 就启动了。打开`http://localhost:8080`就能看到界面。 ```bash docker-compose up -d ``` Docker部署的详情,请见[相关文档](https://docs.crawlab.cn/zh/guide/installation/docker.html)。 ## 截图 #### 登陆页 ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-login.png?raw=true) #### 主页 ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-home.png?raw=true) #### 节点列表 ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-node-list.png?raw=true) #### 爬虫列表 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-list.png?raw=true) #### 爬虫概览 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-detail-overview.png?raw=true) #### 爬虫文件 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-detail-files.png?raw=true) #### 任务日志 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-task-detail-logs.png?raw=true) #### 任务结果 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-task-detail-data.png?raw=true) #### 定时任务 ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-schedule-detail-overview.png?raw=true) ## 架构 Crawlab的架构包括了一个主节点(Master Node)和多个工作节点(Worker Node),以及 [SeaweedFS](https://github.com/chrislusf/seaweedfs) (分布式文件系统) 和 MongoDB 数据库。 ![](https://github.com/crawlab-team/images/blob/main/20210729/crawlab-architecture-v0.6.png?raw=true) 前端应用与主节点 (Master Node) 进行交互,主节点与其他模块(例如 MongoDB、SeaweedFS、工作节点)进行通信。主节点和工作节点 (Worker Nodes) 通过 [gRPC](https://grpc.io) (一种 RPC 框架) 进行通信。任务通过主节点上的任务调度器 (Task Scheduler) 进行调度分发,并被工作节点上的任务处理模块 (Task Handler) 接收,然后分配到任务执行器 (Task Runners) 中。任务执行器实际上是执行爬虫程序的进程,它可以通过 gRPC (内置于 SDK) 发送数据到其他数据源中,例如 MongoDB。 ### 主节点 主节点是整个Crawlab架构的核心,属于Crawlab的中控系统。 主节点主要负责以下功能: 1. 爬虫任务调度 2. 工作节点管理和通信 3. 爬虫部署 4. 前端以及API服务 5. 执行任务(可以将主节点当成工作节点) 主节点负责与前端应用进行通信,并将爬虫任务派发给工作节点。同时,主节点会同步(部署)爬虫到分布式文件系统 SeaweedFS,用于工作节点的文件同步。 ### 工作节点 工作节点的主要功能是执行爬虫任务和储存抓取数据与日志,并且通过Redis的`PubSub`跟主节点通信。通过增加工作节点数量,Crawlab可以做到横向扩展,不同的爬虫任务可以分配到不同的节点上执行。 ### MongoDB MongoDB是Crawlab的运行数据库,储存有节点、爬虫、任务、定时任务等数据。任务队列也储存在 MongoDB 里。 ### SeaweedFS SeaweedFS 是开源分布式文件系统,由 [Chris Lu](https://github.com/chrislusf) 开发和维护。它能在分布式系统中有效稳定的储存和共享文件。在 Crawlab 中,SeaweedFS 主要用作文件同步和日志存储。 ### 前端 Frontend app is built upon [Element-Plus](https://github.com/element-plus/element-plus), a popular [Vue 3](https://github.com/vuejs/vue-next)-based UI framework. It interacts with API hosted on the Master Node, and indirectly controls Worker Nodes. 前端应用是基于 [Element-Plus](https://github.com/element-plus/element-plus) 构建的,它是基于 [Vue 3](https://github.com/vuejs/vue-next) 的 UI 框架。前端应用与主节点上的 API 进行交互,并间接控制工作节点。 ## 与其他框架的集成 [Crawlab SDK](https://github.com/crawlab-team/crawlab-sdk) 提供了一些 `helper` 方法来让您的爬虫更好的集成到 Crawlab 中,例如保存结果数据到 Crawlab 中等等。 ### 集成 Scrapy 在 `settings.py` 中找到 `ITEM_PIPELINES`(`dict` 类型的变量),在其中添加如下内容。 ```python ITEM_PIPELINES = { 'crawlab.scrapy.pipelines.CrawlabPipeline': 888, } ``` 然后,启动 Scrapy 爬虫,运行完成之后,您就应该能看到抓取结果出现在 **任务详情 -> 数据** 里。 ### 通用 Python 爬虫 将下列代码加入到您爬虫中的结果保存部分。 ```python # 引入保存结果方法 from crawlab import save_item # 这是一个结果,需要为 dict 类型 result = {'name': 'crawlab'} # 调用保存结果方法 save_item(result) ``` 然后,启动爬虫,运行完成之后,您就应该能看到抓取结果出现在 **任务详情 -> 数据** 里。 ### 其他框架和语言 爬虫任务实际上是通过 shell 命令执行的。任务 ID (Task ID) 作为环境变量 `CRAWLAB_TASK_ID` 被传入爬虫任务进程中,从而抓取的数据可以跟任务管理。 ## 与其他框架比较 现在已经有一些爬虫管理框架了,因此为啥还要用Crawlab? 因为很多现有当平台都依赖于Scrapyd,限制了爬虫的编程语言以及框架,爬虫工程师只能用scrapy和python。当然,scrapy是非常优秀的爬虫框架,但是它不能做一切事情。 Crawlab使用起来很方便,也很通用,可以适用于几乎任何主流语言和框架。它还有一个精美的前端界面,让用户可以方便的管理和运行爬虫。 |框架 | 技术 | 优点 | 缺点 | Github 统计数据 | |:---|:---|:---|-----| :---- | | [Crawlab](https://github.com/crawlab-team/crawlab) | Golang + Vue|不局限于 scrapy,可以运行任何语言和框架的爬虫,精美的 UI 界面,天然支持分布式爬虫,支持节点管理、爬虫管理、任务管理、定时任务、结果导出、数据统计、消息通知、可配置爬虫、在线编辑代码等功能|暂时不支持爬虫版本管理| ![](https://img.shields.io/github/stars/crawlab-team/crawlab) ![](https://img.shields.io/github/forks/crawlab-team/crawlab) | | [ScrapydWeb](https://github.com/my8100/scrapydweb) | Python Flask + Vue|精美的 UI 界面,内置了 scrapy 日志解析器,有较多任务运行统计图表,支持节点管理、定时任务、邮件提醒、移动界面,算是 scrapy-based 中功能完善的爬虫管理平台|不支持 scrapy 以外的爬虫,Python Flask 为后端,性能上有一定局限性| ![](https://img.shields.io/github/stars/my8100/scrapydweb) ![](https://img.shields.io/github/forks/my8100/scrapydweb) | | [Gerapy](https://github.com/Gerapy/Gerapy) | Python Django + Vue|Gerapy 是崔庆才大神开发的爬虫管理平台,安装部署非常简单,同样基于 scrapyd,有精美的 UI 界面,支持节点管理、代码编辑、可配置规则等功能|同样不支持 scrapy 以外的爬虫,而且据使用者反馈,1.0 版本有很多 bug,期待 2.0 版本会有一定程度的改进| ![](https://img.shields.io/github/stars/Gerapy/Gerapy) ![](https://img.shields.io/github/forks/Gerapy/Gerapy) | | [SpiderKeeper](https://github.com/DormyMo/SpiderKeeper) | Python Flask|基于 scrapyd,开源版 Scrapyhub,非常简洁的 UI 界面,支持定时任务|可能有些过于简洁了,不支持分页,不支持节点管理,不支持 scrapy 以外的爬虫| ![](https://img.shields.io/github/stars/DormyMo/SpiderKeeper) ![](https://img.shields.io/github/forks/DormyMo/SpiderKeeper) | ## 贡献者 ## JetBrains 支持

## 社区 如果您觉得Crawlab对您的日常开发或公司有帮助,请加作者微信 tikazyq1 并注明"Crawlab",作者会将你拉入群。

================================================ FILE: README.md ================================================ # Crawlab

[中文](https://github.com/crawlab-team/crawlab/blob/main/README-zh.md) | English [Installation](#installation) | [Run](#run) | [Screenshot](#screenshot) | [Architecture](#architecture) | [Integration](#integration-with-other-frameworks) | [Compare](#comparison-with-other-frameworks) | [Community & Sponsorship](#community--sponsorship) | [CHANGELOG](https://github.com/crawlab-team/crawlab/blob/main/CHANGELOG.md) | [Disclaimer](https://github.com/crawlab-team/crawlab/blob/main/DISCLAIMER.md) Golang-based distributed web crawler management platform, supporting various languages including Python, NodeJS, Go, Java, PHP and various web crawler frameworks including Scrapy, Puppeteer, Selenium. [Demo](https://demo.crawlab.cn) | [Documentation](https://docs.crawlab.cn/en/) ## Installation You can follow the [installation guide](https://docs.crawlab.cn/en/guide/installation/). ## Quick Start Please open the command line prompt and execute the command below. Make sure you have installed `docker-compose` in advance. ```bash git clone https://github.com/crawlab-team/examples cd examples/docker/basic docker-compose up -d ``` Next, you can look into the `docker-compose.yml` (with detailed config params) and the [Documentation](http://docs.crawlab.cn/en/) for further information. ## Run ### Docker Please use `docker-compose` to one-click to start up. By doing so, you don't even have to configure MongoDB database. Create a file named `docker-compose.yml` and input the code below. ```yaml version: '3.3' services: master: image: crawlabteam/crawlab:latest container_name: crawlab_example_master environment: CRAWLAB_NODE_MASTER: "Y" CRAWLAB_MONGO_HOST: "mongo" volumes: - "./.crawlab/master:/root/.crawlab" ports: - "8080:8080" depends_on: - mongo worker01: image: crawlabteam/crawlab:latest container_name: crawlab_example_worker01 environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" volumes: - "./.crawlab/worker01:/root/.crawlab" depends_on: - master worker02: image: crawlabteam/crawlab:latest container_name: crawlab_example_worker02 environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" volumes: - "./.crawlab/worker02:/root/.crawlab" depends_on: - master mongo: image: mongo:4.2 container_name: crawlab_example_mongo restart: always ``` Then execute the command below, and Crawlab Master and Worker Nodes + MongoDB will start up. Open the browser and enter `http://localhost:8080` to see the UI interface. ```bash docker-compose up -d ``` For Docker Deployment details, please refer to [relevant documentation](https://docs.crawlab.cn/en/guide/installation/docker.html). ## Screenshot #### Login ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-login.png?raw=true) #### Home Page ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-home.png?raw=true) #### Node List ![]( https://github.com/crawlab-team/images/blob/main/20210729/screenshot-node-list.png?raw=true) #### Spider List ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-list.png?raw=true) #### Spider Overview ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-detail-overview.png?raw=true) #### Spider Files ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-spider-detail-files.png?raw=true) #### Task Log ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-task-detail-logs.png?raw=true) #### Task Results ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-task-detail-data.png?raw=true) #### Cron Job ![](https://github.com/crawlab-team/images/blob/main/20210729/screenshot-schedule-detail-overview.png?raw=true) ## Architecture The architecture of Crawlab is consisted of a master node, worker nodes, [SeaweedFS](https://github.com/chrislusf/seaweedfs) (a distributed file system) and MongoDB database. ![](https://github.com/crawlab-team/images/blob/main/20210729/crawlab-architecture-v0.6.png?raw=true) The frontend app interacts with the master node, which communicates with other components such as MongoDB, SeaweedFS and worker nodes. Master node and worker nodes communicate with each other via [gRPC](https://grpc.io) (a RPC framework). Tasks are scheduled by the task scheduler module in the master node, and received by the task handler module in worker nodes, which executes these tasks in task runners. Task runners are actually processes running spider or crawler programs, and can also send data through gRPC (integrated in SDK) to other data sources, e.g. MongoDB. ### Master Node The Master Node is the core of the Crawlab architecture. It is the center control system of Crawlab. The Master Node provides below services: 1. Task Scheduling; 2. Worker Node Management and Communication; 3. Spider Deployment; 4. Frontend and API Services; 5. Task Execution (you can regard the Master Node as a Worker Node) The Master Node communicates with the frontend app, and send crawling tasks to Worker Nodes. In the mean time, the Master Node uploads (deploys) spiders to the distributed file system SeaweedFS, for synchronization by worker nodes. ### Worker Node The main functionality of the Worker Nodes is to execute crawling tasks and store results and logs, and communicate with the Master Node through gRPC. By increasing the number of Worker Nodes, Crawlab can scale horizontally, and different crawling tasks can be assigned to different nodes to execute. ### MongoDB MongoDB is the operational database of Crawlab. It stores data of nodes, spiders, tasks, schedules, etc. Task queue is also stored in MongoDB. ### SeaweedFS SeaweedFS is an open source distributed file system authored by [Chris Lu](https://github.com/chrislusf). It can robustly store and share files across a distributed system. In Crawlab, SeaweedFS mainly plays the role as file synchronization system and the place where task log files are stored. ### Frontend Frontend app is built upon [Element-Plus](https://github.com/element-plus/element-plus), a popular [Vue 3](https://github.com/vuejs/vue-next)-based UI framework. It interacts with API hosted on the Master Node, and indirectly controls Worker Nodes. ## Integration with Other Frameworks [Crawlab SDK](https://github.com/crawlab-team/crawlab-sdk) provides some `helper` methods to make it easier for you to integrate your spiders into Crawlab, e.g. saving results. ### Scrapy In `settings.py` in your Scrapy project, find the variable named `ITEM_PIPELINES` (a `dict` variable). Add content below. ```python ITEM_PIPELINES = { 'crawlab.scrapy.pipelines.CrawlabPipeline': 888, } ``` Then, start the Scrapy spider. After it's done, you should be able to see scraped results in **Task Detail -> Data** ### General Python Spider Please add below content to your spider files to save results. ```python # import result saving method from crawlab import save_item # this is a result record, must be dict type result = {'name': 'crawlab'} # call result saving method save_item(result) ``` Then, start the spider. After it's done, you should be able to see scraped results in **Task Detail -> Data** ### Other Frameworks / Languages A crawling task is actually executed through a shell command. The Task ID will be passed to the crawling task process in the form of environment variable named `CRAWLAB_TASK_ID`. By doing so, the data can be related to a task. ## Comparison with Other Frameworks There are existing spider management frameworks. So why use Crawlab? The reason is that most of the existing platforms are depending on Scrapyd, which limits the choice only within python and scrapy. Surely scrapy is a great web crawl framework, but it cannot do everything. Crawlab is easy to use, general enough to adapt spiders in any language and any framework. It has also a beautiful frontend interface for users to manage spiders much more easily. |Framework | Technology | Pros | Cons | Github Stats | |:---|:---|:---|-----| :---- | | [Crawlab](https://github.com/crawlab-team/crawlab) | Golang + Vue|Not limited to Scrapy, available for all programming languages and frameworks. Beautiful UI interface. Naturally support distributed spiders. Support spider management, task management, cron job, result export, analytics, notifications, configurable spiders, online code editor, etc.|Not yet support spider versioning| ![](https://img.shields.io/github/stars/crawlab-team/crawlab) ![](https://img.shields.io/github/forks/crawlab-team/crawlab) | | [ScrapydWeb](https://github.com/my8100/scrapydweb) | Python Flask + Vue|Beautiful UI interface, built-in Scrapy log parser, stats and graphs for task execution, support node management, cron job, mail notification, mobile. Full-feature spider management platform.|Not support spiders other than Scrapy. Limited performance because of Python Flask backend.| ![](https://img.shields.io/github/stars/my8100/scrapydweb) ![](https://img.shields.io/github/forks/my8100/scrapydweb) | | [Gerapy](https://github.com/Gerapy/Gerapy) | Python Django + Vue|Gerapy is built by web crawler guru [Germey Cui](https://github.com/Germey). Simple installation and deployment. Beautiful UI interface. Support node management, code edit, configurable crawl rules, etc.|Again not support spiders other than Scrapy. A lot of bugs based on user feedback in v1.0. Look forward to improvement in v2.0| ![](https://img.shields.io/github/stars/Gerapy/Gerapy) ![](https://img.shields.io/github/forks/Gerapy/Gerapy) | | [SpiderKeeper](https://github.com/DormyMo/SpiderKeeper) | Python Flask|Open-source Scrapyhub. Concise and simple UI interface. Support cron job.|Perhaps too simplified, not support pagination, not support node management, not support spiders other than Scrapy.| ![](https://img.shields.io/github/stars/DormyMo/SpiderKeeper) ![](https://img.shields.io/github/forks/DormyMo/SpiderKeeper) | ## Contributors ## Supported by JetBrains

## Community If you feel Crawlab could benefit your daily work or your company, please add the author's Wechat account noting "Crawlab" to enter the discussion group.

================================================ FILE: SECURITY.md ================================================ # Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | 0.6.x | :white_check_mark: | | 0.5.x | :white_check_mark: | | < 0.5 | :x: | ## Reporting a Vulnerability If you encounter a security vulnerability, please submit an issue with tag "security" and highlight the reasons and impact of the security vulnerability. ================================================ FILE: backend/.air.master.conf ================================================ # Config file for [Air](https://github.com/cosmtrek/air) in TOML format # Working directory # . or absolute path, please note that the directories following must be under root. root = "." tmp_dir = "/tmp" [build] # Just plain old shell command. You could use `make` as well. cmd = "go build -o ../tmp/main ./ " # Binary file yields from `cmd`. bin = "../tmp/main" # Customize binary. full_bin = "../tmp/main master" # Watch these filename extensions. include_ext = ["go", "tpl", "tmpl", "html"] # Ignore these filename extensions or directories. exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"] # Watch these directories if you specified. include_dir = ["../libs"] # Exclude files. exclude_file = [] # This log file places in your tmp_dir. log = "air.log" # It's not necessary to trigger build each time file changes if it's too frequent. delay = 1000 # ms # Stop running old binary when build errors occur. stop_on_error = true # Send Interrupt signal before killing process (windows does not support this feature) send_interrupt = false # Delay after sending Interrupt signal kill_delay = 500 # ms [log] # Show log time time = false [color] # Customize each part's color. If no color found, use the raw app log. main = "magenta" watcher = "cyan" build = "yellow" runner = "green" [misc] # Delete tmp directory on exit clean_on_exit = true ================================================ FILE: backend/.air.worker.conf ================================================ # Config file for [Air](https://github.com/cosmtrek/air) in TOML format # Working directory # . or absolute path, please note that the directories following must be under root. root = "." tmp_dir = "/tmp" [build] # Just plain old shell command. You could use `make` as well. cmd = "go build -o ../tmp/main ./ " # Binary file yields from `cmd`. bin = "../tmp/main" # Customize binary. full_bin = "../tmp/main worker" # Watch these filename extensions. include_ext = ["go", "tpl", "tmpl", "html"] # Ignore these filename extensions or directories. exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"] # Watch these directories if you specified. include_dir = ["../libs"] # Exclude files. exclude_file = [] # This log file places in your tmp_dir. log = "air.log" # It's not necessary to trigger build each time file changes if it's too frequent. delay = 1000 # ms # Stop running old binary when build errors occur. stop_on_error = true # Send Interrupt signal before killing process (windows does not support this feature) send_interrupt = false # Delay after sending Interrupt signal kill_delay = 500 # ms [log] # Show log time time = false [color] # Customize each part's color. If no color found, use the raw app log. main = "magenta" watcher = "cyan" build = "yellow" runner = "green" [misc] # Delete tmp directory on exit clean_on_exit = true ================================================ FILE: backend/.editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true [{*.yml, *.yaml, *.json}] indent_size = 2 ================================================ FILE: backend/Dockerfile ================================================ FROM golang:1.18 AS build WORKDIR /go/src/app COPY . . ENV GO111MODULE on #ENV GOPROXY https://goproxy.io RUN go mod tidy \ && go install -v ./... FROM alpine:3.14 # copy files COPY --from=build /go/bin/crawlab /go/bin/crawlab ================================================ FILE: backend/README.md ================================================ # crawlab-backend Backend (Golang) for Crawlab ================================================ FILE: backend/Taskfile.yml ================================================ version: '3' tasks: dev: desc: Switch to dev mode for local development. cmds: - cp -f go.mod.dev go.mod deploy: desc: Switch to deploy mode for code publish. cmds: - echo 'not implemented' ================================================ FILE: backend/bin/semver.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 set -o errexit -o nounset -o pipefail NAT='0|[1-9][0-9]*' ALPHANUM='[0-9]*[A-Za-z-][0-9A-Za-z-]*' IDENT="$NAT|$ALPHANUM" FIELD='[0-9A-Za-z-]+' SEMVER_REGEX="\ ^[vV]?\ ($NAT)\\.($NAT)\\.($NAT)\ (\\-(${IDENT})(\\.(${IDENT}))*)?\ (\\+${FIELD}(\\.${FIELD})*)?$" PROG=semver PROG_VERSION="3.4.0" USAGE="\ Usage: $PROG bump major $PROG bump minor $PROG bump patch $PROG bump prerel|prerelease [] $PROG bump build $PROG bump release $PROG get major $PROG get minor $PROG get patch $PROG get prerel|prerelease $PROG get build $PROG get release $PROG compare $PROG diff $PROG validate $PROG --help $PROG --version Arguments: A version must match the following regular expression: \"${SEMVER_REGEX}\" In English: -- The version must match X.Y.Z[-PRERELEASE][+BUILD] where X, Y and Z are non-negative integers. -- PRERELEASE is a dot separated sequence of non-negative integers and/or identifiers composed of alphanumeric characters and hyphens (with at least one non-digit). Numeric identifiers must not have leading zeros. A hyphen (\"-\") introduces this optional part. -- BUILD is a dot separated sequence of identifiers composed of alphanumeric characters and hyphens. A plus (\"+\") introduces this optional part. See definition. A string as defined by PRERELEASE above. Or, it can be a PRERELEASE prototype string followed by a dot. A string as defined by BUILD above. Options: -v, --version Print the version of this tool. -h, --help Print this help message. Commands: bump Bump by one of major, minor, patch; zeroing or removing subsequent parts. \"bump prerel\" (or its synonym \"bump prerelease\") sets the PRERELEASE part and removes any BUILD part. A trailing dot in the argument introduces an incrementing numeric field which is added or bumped. If no argument is provided, an incrementing numeric field is introduced/bumped. \"bump build\" sets the BUILD part. \"bump release\" removes any PRERELEASE or BUILD parts. The bumped version is written to stdout. get Extract given part of , where part is one of major, minor, patch, prerel (alternatively: prerelease), build, or release. compare Compare with , output to stdout the following values: -1 if is newer, 0 if equal, 1 if older. The BUILD part is not used in comparisons. diff Compare with , output to stdout the difference between two versions by the release type (MAJOR, MINOR, PATCH, PRERELEASE, BUILD). validate Validate if follows the SEMVER pattern (see definition). Print 'valid' to stdout if the version is valid, otherwise print 'invalid'. See also: https://semver.org -- Semantic Versioning 2.0.0" function error { echo -e "$1" >&2 exit 1 } function usage_help { error "$USAGE" } function usage_version { echo -e "${PROG}: $PROG_VERSION" exit 0 } # normalize the "part" keywords to a canonical string. At present, # only "prerelease" is normalized to "prerel". function normalize_part { if [ "$1" == "prerelease" ] then echo "prerel" else echo "$1" fi } function validate_version { local version=$1 if [[ "$version" =~ $SEMVER_REGEX ]]; then # if a second argument is passed, store the result in var named by $2 if [ "$#" -eq "2" ]; then local major=${BASH_REMATCH[1]} local minor=${BASH_REMATCH[2]} local patch=${BASH_REMATCH[3]} local prere=${BASH_REMATCH[4]} local build=${BASH_REMATCH[8]} eval "$2=(\"$major\" \"$minor\" \"$patch\" \"$prere\" \"$build\")" else echo "$version" fi else error "version $version does not match the semver scheme 'X.Y.Z(-PRERELEASE)(+BUILD)'. See help for more information." fi } function is_nat { [[ "$1" =~ ^($NAT)$ ]] } function is_null { [ -z "$1" ] } function order_nat { [ "$1" -lt "$2" ] && { echo -1 ; return ; } [ "$1" -gt "$2" ] && { echo 1 ; return ; } echo 0 } function order_string { [[ $1 < $2 ]] && { echo -1 ; return ; } [[ $1 > $2 ]] && { echo 1 ; return ; } echo 0 } # given two (named) arrays containing NAT and/or ALPHANUM fields, compare them # one by one according to semver 2.0.0 spec. Return -1, 0, 1 if left array ($1) # is less-than, equal, or greater-than the right array ($2). The longer array # is considered greater-than the shorter if the shorter is a prefix of the longer. # function compare_fields { local l="$1[@]" local r="$2[@]" local leftfield=( "${!l}" ) local rightfield=( "${!r}" ) local left local right local i=$(( -1 )) local order=$(( 0 )) while true do [ $order -ne 0 ] && { echo $order ; return ; } : $(( i++ )) left="${leftfield[$i]}" right="${rightfield[$i]}" is_null "$left" && is_null "$right" && { echo 0 ; return ; } is_null "$left" && { echo -1 ; return ; } is_null "$right" && { echo 1 ; return ; } is_nat "$left" && is_nat "$right" && { order=$(order_nat "$left" "$right") ; continue ; } is_nat "$left" && { echo -1 ; return ; } is_nat "$right" && { echo 1 ; return ; } { order=$(order_string "$left" "$right") ; continue ; } done } # shellcheck disable=SC2206 # checked by "validate"; ok to expand prerel id's into array function compare_version { local order validate_version "$1" V validate_version "$2" V_ # compare major, minor, patch local left=( "${V[0]}" "${V[1]}" "${V[2]}" ) local right=( "${V_[0]}" "${V_[1]}" "${V_[2]}" ) order=$(compare_fields left right) [ "$order" -ne 0 ] && { echo "$order" ; return ; } # compare pre-release ids when M.m.p are equal local prerel="${V[3]:1}" local prerel_="${V_[3]:1}" local left=( ${prerel//./ } ) local right=( ${prerel_//./ } ) # if left and right have no pre-release part, then left equals right # if only one of left/right has pre-release part, that one is less than simple M.m.p [ -z "$prerel" ] && [ -z "$prerel_" ] && { echo 0 ; return ; } [ -z "$prerel" ] && { echo 1 ; return ; } [ -z "$prerel_" ] && { echo -1 ; return ; } # otherwise, compare the pre-release id's compare_fields left right } # render_prerel -- return a prerel field with a trailing numeric string # usage: render_prerel numeric [prefix-string] # function render_prerel { if [ -z "$2" ] then echo "${1}" else echo "${2}${1}" fi } # extract_prerel -- extract prefix and trailing numeric portions of a pre-release part # usage: extract_prerel prerel prerel_parts # The prefix and trailing numeric parts are returned in "prerel_parts". # PREFIX_ALPHANUM='[.0-9A-Za-z-]*[.A-Za-z-]' DIGITS='[0-9][0-9]*' EXTRACT_REGEX="^(${PREFIX_ALPHANUM})*(${DIGITS})$" function extract_prerel { local prefix; local numeric; if [[ "$1" =~ $EXTRACT_REGEX ]] then # found prefix and trailing numeric parts prefix="${BASH_REMATCH[1]}" numeric="${BASH_REMATCH[2]}" else # no numeric part prefix="${1}" numeric= fi eval "$2=(\"$prefix\" \"$numeric\")" } # bump_prerel -- return the new pre-release part based on previous pre-release part # and prototype for bump # usage: bump_prerel proto previous # function bump_prerel { local proto; local prev_prefix; local prev_numeric; # case one: no trailing dot in prototype => simply replace previous with proto if [[ ! ( "$1" =~ \.$ ) ]] then echo "$1" return fi proto="${1%.}" # discard trailing dot marker from prototype extract_prerel "${2#-}" prerel_parts # extract parts of previous pre-release # shellcheck disable=SC2154 prev_prefix="${prerel_parts[0]}" prev_numeric="${prerel_parts[1]}" # case two: bump or append numeric to previous pre-release part if [ "$proto" == "+" ] # dummy "+" indicates no prototype argument provided then if [ -n "$prev_numeric" ] then : $(( ++prev_numeric )) # previous pre-release is already numbered, bump it render_prerel "$prev_numeric" "$prev_prefix" else render_prerel 1 "$prev_prefix" # append starting number fi return fi # case three: set, bump, or append using prototype prefix if [ "$prev_prefix" != "$proto" ] then render_prerel 1 "$proto" # proto not same pre-release; set and start at '1' elif [ -n "$prev_numeric" ] then : $(( ++prev_numeric )) # pre-release is numbered; bump it render_prerel "$prev_numeric" "$prev_prefix" else render_prerel 1 "$prev_prefix" # start pre-release at number '1' fi } function command_bump { local new; local version; local sub_version; local command; command="$(normalize_part "$1")" case $# in 2) case "$command" in major|minor|patch|prerel|release) sub_version="+."; version=$2;; *) usage_help;; esac ;; 3) case "$command" in prerel|build) sub_version=$2 version=$3 ;; *) usage_help;; esac ;; *) usage_help;; esac validate_version "$version" parts # shellcheck disable=SC2154 local major="${parts[0]}" local minor="${parts[1]}" local patch="${parts[2]}" local prere="${parts[3]}" local build="${parts[4]}" case "$command" in major) new="$((major + 1)).0.0";; minor) new="${major}.$((minor + 1)).0";; patch) new="${major}.${minor}.$((patch + 1))";; release) new="${major}.${minor}.${patch}";; prerel) new=$(validate_version "${major}.${minor}.${patch}-$(bump_prerel "$sub_version" "$prere")");; build) new=$(validate_version "${major}.${minor}.${patch}${prere}+${sub_version}");; *) usage_help ;; esac echo "$new" exit 0 } function command_compare { local v; local v_; case $# in 2) v=$(validate_version "$1"); v_=$(validate_version "$2") ;; *) usage_help ;; esac set +u # need unset array element to evaluate to null compare_version "$v" "$v_" exit 0 } function command_diff { validate_version "$1" v1_parts # shellcheck disable=SC2154 local v1_major="${v1_parts[0]}" local v1_minor="${v1_parts[1]}" local v1_patch="${v1_parts[2]}" local v1_prere="${v1_parts[3]}" local v1_build="${v1_parts[4]}" validate_version "$2" v2_parts # shellcheck disable=SC2154 local v2_major="${v2_parts[0]}" local v2_minor="${v2_parts[1]}" local v2_patch="${v2_parts[2]}" local v2_prere="${v2_parts[3]}" local v2_build="${v2_parts[4]}" if [ "${v1_major}" != "${v2_major}" ]; then echo "major" elif [ "${v1_minor}" != "${v2_minor}" ]; then echo "minor" elif [ "${v1_patch}" != "${v2_patch}" ]; then echo "patch" elif [ "${v1_prere}" != "${v2_prere}" ]; then echo "prerelease" elif [ "${v1_build}" != "${v2_build}" ]; then echo "build" fi } # shellcheck disable=SC2034 function command_get { local part version if [[ "$#" -ne "2" ]] || [[ -z "$1" ]] || [[ -z "$2" ]]; then usage_help exit 0 fi part="$1" version="$2" validate_version "$version" parts local major="${parts[0]}" local minor="${parts[1]}" local patch="${parts[2]}" local prerel="${parts[3]:1}" local build="${parts[4]:1}" local release="${major}.${minor}.${patch}" part="$(normalize_part "$part")" case "$part" in major|minor|patch|release|prerel|build) echo "${!part}" ;; *) usage_help ;; esac exit 0 } function command_validate { if [[ "$#" -ne "1" ]]; then usage_help fi if [[ "$1" =~ $SEMVER_REGEX ]]; then echo "valid" else echo "invalid" fi exit 0 } case $# in 0) echo "Unknown command: $*"; usage_help;; esac case $1 in --help|-h) echo -e "$USAGE"; exit 0;; --version|-v) usage_version ;; bump) shift; command_bump "$@";; get) shift; command_get "$@";; compare) shift; command_compare "$@";; diff) shift; command_diff "$@";; validate) shift; command_validate "$@";; *) echo "Unknown arguments: $*"; usage_help;; esac ================================================ FILE: backend/bin/update-deps.sh ================================================ #!/bin/bash go get -u github.com/crawlab-team/crawlab/core@main go mod tidy ================================================ FILE: backend/bin/update-ver.sh ================================================ #!/bin/sh # update version type (major, minor, patch, prerelease) update_version_type="prerelease" if [ -n "$1" ]; then update_version_type="$1" fi # current version current_version=$(grep -oEi 'version: v([0-9\.?]+)' conf/config.yml | sed -E 's/version: v//g') # next version next_version=$(./bin/semver.sh bump $update_version_type $current_version) # update next version to conf/config.yml sed -i '' "s/version: v$current_version/version: v$next_version/g" conf/config.yml ================================================ FILE: backend/conf/config.yml ================================================ # Crawlab Configuration File edition: global.edition.community version: v0.6.3 mongo: host: localhost port: 27017 db: crawlab_test username: "" password: "" authSource: "admin" server: host: 0.0.0.0 port: 8000 grpc: address: localhost:9666 server: address: 0.0.0.0:9666 authKey: Crawlab2021! api: endpoint: http://localhost:8000 log: path: /var/log/crawlab ================================================ FILE: backend/go.mod ================================================ module crawlab go 1.22 replace ( github.com/crawlab-team/crawlab/core => ../core github.com/crawlab-team/crawlab/db => ../db github.com/crawlab-team/crawlab/fs => ../fs github.com/crawlab-team/crawlab/grpc => ../grpc github.com/crawlab-team/crawlab/template-parser => ../template-parser github.com/crawlab-team/crawlab/trace => ../trace github.com/crawlab-team/crawlab/vcs => ../vcs ) require github.com/crawlab-team/crawlab/core v0.0.0-20240614095218-7b4ee8399ab0 require ( dario.cat/mergo v1.0.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/sirupsen/logrus v1.9.0 // indirect ) require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/Masterminds/semver v1.4.2 // indirect github.com/Masterminds/sprig v2.16.0+incompatible // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/PuerkitoBio/goquery v1.8.0 // indirect github.com/ReneKroon/ttlcache v1.7.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect github.com/aokoli/goutils v1.0.1 // indirect github.com/apex/log v1.9.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cenkalti/backoff/v4 v4.1.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/crawlab-team/crawlab/db v0.0.0-20240614095218-7b4ee8399ab0 // indirect github.com/crawlab-team/crawlab/fs v0.0.0-20240614095218-7b4ee8399ab0 // indirect github.com/crawlab-team/crawlab/grpc v0.0.0-20240614111723-e5b20af9a40b // indirect github.com/crawlab-team/crawlab/template-parser v0.0.0-20240614095218-7b4ee8399ab0 // indirect github.com/crawlab-team/crawlab/trace v0.0.0-20240614095218-7b4ee8399ab0 // indirect github.com/crawlab-team/crawlab/vcs v0.0.0-20240614095218-7b4ee8399ab0 // indirect github.com/crawlab-team/goseaweedfs v0.6.3 // indirect github.com/denisenkom/go-mssqldb v0.11.0 // indirect github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect github.com/elastic/go-elasticsearch/v8 v8.14.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-git/go-git/v5 v5.12.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.2.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/imroc/req v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.11.0 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/pgtype v1.10.0 // indirect github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/matcornic/hermes/v2 v2.1.0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.3 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/olekukonko/tablewriter v0.0.1 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 // indirect github.com/robfig/cron/v3 v3.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/segmentio/fasthash v1.0.3 // indirect github.com/segmentio/kafka-go v0.4.39 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cobra v1.3.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/thoas/go-funk v0.9.1 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/numcpus v0.3.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/upper/db/v4 v4.6.0 // indirect github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 // indirect github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/ztrue/tracerr v0.4.0 // indirect go.mongodb.org/mongo-driver v1.15.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/dig v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.20.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: backend/go.mod.dev ================================================ module crawlab go 1.16 replace ( github.com/crawlab-team/crawlab/core => ../../crawlab-core github.com/crawlab-team/crawlab-vcs => ../../crawlab-vcs github.com/crawlab-team/crawlab/fs => ../../crawlab-fs github.com/crawlab-team/crawlab/db => ../../crawlab-db ) require ( github.com/apex/log v1.9.0 github.com/crawlab-team/crawlab/core v0.6.0-beta.20211230.1200 github.com/crawlab-team/crawlab/vcs v0.1.1 github.com/gin-gonic/gin v1.7.1 github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.1 go.uber.org/dig v1.10.0 ) ================================================ FILE: backend/go.mod.local ================================================ module crawlab go 1.16 replace ( github.com/crawlab-team/crawlab/core => /libs/crawlab-team/crawlab-core github.com/crawlab-team/crawlab-vcs => /libs/crawlab-team/crawlab-vcs github.com/crawlab-team/crawlab/fs => /libs/crawlab-team/crawlab-fs github.com/crawlab-team/crawlab/db => /libs/crawlab-team/crawlab-db ) require ( github.com/apex/log v1.9.0 github.com/crawlab-team/crawlab/core v0.6.0-beta.20211230.1200 github.com/crawlab-team/crawlab/vcs v0.1.1 github.com/gin-gonic/gin v1.7.1 github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.1 go.uber.org/dig v1.10.0 ) ================================================ FILE: backend/go.sum ================================================ 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 v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 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/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= github.com/ReneKroon/ttlcache v1.7.0 h1:8BkjFfrzVFXyrqnMtezAaJ6AHPSsVV10m6w28N/Fgkk= github.com/ReneKroon/ttlcache v1.7.0/go.mod h1:8BGGzdumrIjWxdRx8zpK6L3oGMWvIXdvB2GD1cfvd+I= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 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.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= 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-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 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/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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 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/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 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/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crawlab-team/goseaweedfs v0.6.3 h1:f96H2QCLrZpof9na1mhIKouKrv8p32XRUyouSVm4YHU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA= github.com/elastic/go-elasticsearch/v8 v8.14.0 h1:1ywU8WFReLLcxE1WJqii3hTtbPUE2hc38ZK/j4mMFow= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gavv/httpexpect/v2 v2.16.0 h1:Ty2favARiTYTOkCRZGX7ojXXjGyNAIohM1lZ3vqaEwI= github.com/gavv/httpexpect/v2 v2.16.0/go.mod h1:uJLaO+hQ25ukBJtQi750PsztObHybNllN+t+MbbW8PY= 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= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/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.1/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-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 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/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= 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.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/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/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-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 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-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 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/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 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.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= 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/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.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/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ= github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w= github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 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= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/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.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matcornic/hermes/v2 v2.1.0 h1:9TDYFBPFv6mcXanaDmRDEp/RTWj0dTTi+LpFnnnfNWc= github.com/matcornic/hermes/v2 v2.1.0/go.mod h1:2+ziJeoyRfaLiATIL8VZ7f9hpzH4oDHqTmn0bhrsgVI= 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-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 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.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.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/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= 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/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= 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/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 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/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 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/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 h1:ewTtJ72GFy2e0e8uyiDwMG3pKCS5mBh+hdSTYsPKEP8= github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= 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/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/kafka-go v0.4.39 h1:75smaomhvkYRwtuOwqLsdhgCG30B82NsbdkdDfFbvrw= github.com/segmentio/kafka-go v0.4.39/go.mod h1:T0MLgygYvmqmBvC+s8aCcbVNfJN4znVne5j0Pzowp/Q= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 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.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= 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/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/upper/db/v4 v4.6.0 h1:0VmASnqrl/XN8Ehoq++HBgZ4zRD5j3GXygW8FhP0C5I= github.com/upper/db/v4 v4.6.0/go.mod h1:2mnRcPf+RcCXmVcD+o04LYlyu3UuF7ubamJia7CkN6s= 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.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4= github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 h1:L0rPdfzq43+NV8rfIx2kA4iSSLRj2jN5ijYHoeXRwvQ= github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w= github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe h1:9YnI5plmy+ad6BM+JCLJb2ZV7/TNiE5l7SNKfumYKgc= github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe/go.mod h1:JTFJA/t820uFDoyPpErFQ3rb3amdZoPtxcKervG0OE4= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw= github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4= github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/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.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 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/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 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/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04= github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= 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.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 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/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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-20181029175232-7e6ffbd03851/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 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/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/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-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-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-20190225065934-cc5685c2db12/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/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-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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/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-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/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= 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/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= 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.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/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-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= 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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= 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= 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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/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= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= modernc.org/b v1.0.2/go.mod h1:fVGfCIzkZw5RsuF2A2WHbJmY7FiMIq30nP4s52uWsoY= modernc.org/db v1.0.3/go.mod h1:L4ltUg8tu2pkSJk+fKaRrXs/3EdW79ZKYQ5PfVDT53U= modernc.org/file v1.0.3/go.mod h1:CNj/pwOfCtCbqiHcXDUlHBB2vWrzdaDCWdcnjtS1+XY= modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254= modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= modernc.org/internal v1.0.2/go.mod h1:bycJAcev709ZU/47nil584PeBD+kbu8nv61ozeMso9E= modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk= modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk= modernc.org/lldb v1.0.2/go.mod h1:ovbKqyzA9H/iPwHkAOH0qJbIQVT9rlijecenxDwVUi0= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/ql v1.4.0/go.mod h1:q4c29Bgdx+iAtxx47ODW5Xo2X0PDkjSCK9NdQl6KFxc= modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/zappy v1.0.3/go.mod h1:w/Akq8ipfols/xZJdR5IYiQNOqC80qz2mVvsEwEbkiI= moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= ================================================ FILE: backend/main.go ================================================ package main import ( "github.com/crawlab-team/crawlab/core/cmd" ) func main() { _ = cmd.Execute() } ================================================ FILE: backend/test/config-master.json ================================================ { "key": "master", "is_master": true, "name": "Master Node", "ip": "", "mac": "", "hostname": "", "description": "", "auth_key": "Crawlab2021!" } ================================================ FILE: backend/test/config-worker-01.json ================================================ { "key": "worker-01", "is_master": false, "name": "Worker Node 01", "ip": "", "mac": "", "hostname": "", "description": "", "auth_key": "Crawlab2021!" } ================================================ FILE: backend/test/config-worker-02.json ================================================ { "key": "worker-02", "is_master": false, "name": "Worker Node 02", "ip": "", "mac": "", "hostname": "", "description": "", "auth_key": "Crawlab2021!" } ================================================ FILE: backend/test/config-worker-03.json ================================================ { "key": "worker-03", "is_master": false, "name": "Worker Node 03", "ip": "", "mac": "", "hostname": "", "description": "", "auth_key": "Crawlab2021!" } ================================================ FILE: backend/test/config-worker-invalid-auth-key.json ================================================ { "key": "worker-invalid-auth-key", "is_master": false, "name": "worker", "ip": "", "mac": "", "hostname": "", "description": "", "auth_key": "invalid-auth-key" } ================================================ FILE: bin/docker-init.sh ================================================ #!/bin/bash # replace default api path to new one python /app/bin/update_docker_js_api_address.py crawlab-server server ================================================ FILE: bin/gen-ver.sh ================================================ #!/bin/bash COMMIT_HASH=$(git rev-parse HEAD) TIMESTAMP=$(date +%Y%m%d%H%M%S) echo "v0.0.0-$TIMESTAMP-$COMMIT_HASH" ================================================ FILE: bin/update_docker_js_api_address.py ================================================ import os dir_path = '/app/dist/assets' for file_name in os.listdir(dir_path): if not file_name.endswith('.js'): continue file_path = os.path.join(dir_path, file_name) api_url = 'http://localhost:8000' with open(file_path, 'r') as f: content = f.read() if api_url not in content: continue content = content.replace(api_url, '/api') with open(file_path, 'w') as f: f.write(content) print(f'replaced api url in file: {file_name}') ================================================ FILE: changelog/v0.6.0-zh.md ================================================ # 更新日志 (v0.6.0) ## 概览 作为一个重要版本发布,Crawlab v0.6.0 由一些重大的功能升级组成,包括性能、稳定性、健壮性、易用性方面的大量优化。本次 beta 版本理论上会比老版本更加健壮,特别是任务执行、文件同步、节点通信上面。但是,我们还是推荐用户在 Crawlab 新版本上更全面的测试不同的爬虫任务。 ## 升级优化 #### 后端 - **文件同步**. 将文件同步从原先的 MongoDB GridFS 迁移到分布式文件系统 SeaweedFS,以提升文件同步和爬虫部署的稳定性和健壮性。 - **节点通信**. 将节点通信从原先基于 Redis 套壳的 RPC 迁移到 gRPC。工作节点通过向主节点发起 gRPC 请求来与 MongoDB 数据库间接交互。 - **任务队列**. 将任务队列从 Redis 列表迁移到 MongoDB 集合,以提高灵活性,例如优先级队列。 - **日志**. 将日志储存迁移到 SeaweedFS,以解决 MongoDB 数据库中的性能问题。 - **SDK 集成**. 将结果数据储存从原生 SDK 迁移到了任务处理器集中导入到数据库。 - **任务相关**. 将任务相关逻辑抽象为了任务调度器、任务处理器以及任务执行器,以减少系统耦合度,提升可扩展性和可维护性。 - **组件化**. 引入依赖注入框架,将模块、服务以及子系统进行模块化。 - **插件框架**. **Crawlab 插件框架 (CPF)** 已发布. 详情请参考 [这里](https://docs.crawlab.cn/zh/guide/plugin/). - **Git 集成**. Git 集成被作为内置功能. - **Scrapy 集成**. Scrapy 集成以插件形式存在,插件为 [spider-assistant](https://docs.crawlab.cn/zh/guide/plugin/plugin-spider-assistant.html). - **依赖集成**. Dependency 集成以插件形式存在,插件为 [dependency](https://docs.crawlab.cn/zh/guide/plugin/plugin-dependency). - **消息通知**. 消息通知功能以插件形式存在,插件为 [notification](https://docs.crawlab.cn/zh/guide/plugin/plugin-notification). #### 前端 - **Vue 3**. 迁移到了最新的前端框架 Vue 3,以支持更高级的功能,例如组合式 API 和 TypeScript。 - **UI 框架**. 从之前的 Vue-Element-Admin 迁移到了基于 Vue 3 的 UI 框架 Element-Plus,更多灵活性和功能性。 - **高级文件编辑器**. 支持更高级的文件编辑器功能,包括拖砖操作、复制、移动、重命名、删除、文件编辑、代码高亮、导航标签等。 - **可自定义表格**. 内置更多高级功能,包括自定义列、批量操作、搜索、过滤、排序等。 - **导航标签**. 支持多导航标签查看不同的页面。 - **批量创建**. 支持批量创建对象,包括爬虫、项目、定时任务等。 - **详情导航**. 详情页里的侧边栏导航。 - **更优化的仪表盘**. 主页仪表盘中更多的数据图表。 #### 其他 - **文档网站**. 升级 [文档网站](https://docs-next.crawlab.cn). - **官方插件**. 允许用户在 Crawlab 用户界面上安装 [官方插件](https://docs.crawlab.cn/zh/guide/plugin/). ================================================ FILE: changelog/v0.6.0.md ================================================ # Change Log (v0.6.0) ## Overview As a major release, v0.6.0 is consisted of a number of large changes to enhance the performance, scalability, robustness and usability of Crawlab. This beta version is theoretically more robust than older versions mainly in task execution, files synchronization and node management, yet we still recommend users to thoroughly run tests with various samples. ## Enhancements #### Backend - **File Synchronization**. Migrated file sync from MongoDB GridFS to SeaweedFS for better stability and robustness. - **Node Communication**. Migrated node communication from Redis-based RPC to gRPC. Worker nodes indirectly interact with MongoDB by making gRPC calls to the master node. - **Task Queue**. Migrated task queue from Redis list to MongoDB collection to allow more flexibility (e.g. priority queue). - **Logging**. Migrated logging storage system to SeaweedFS to resolve performance issue in MongoDB. - **SDK Integration**. Migrated results data ingestion from native SDK to task handler side. - **Task Related**. Abstracted task related logics into Task Scheduler, Task Handler and Task Runners to increase decoupling and improve scalability and maintainability. - **Compotenization**. Introduced DI (dependency injection) framework and componentized modules, services and sub-systems. - **Plugin Framework**. **Crawlab Plugin Framework (CPF)** has been released. See more info [here](https://docs.crawlab.cn/en/guide/plugin/). - **Git Integration**. Git integration is implemented as a built-in feature. - **Scrapy Integration**. Scrapy integration is implemented as a plugin [spider-assistant](https://docs.crawlab.cn/en/guide/plugin/plugin-spider-assistant). - **Dependency Integration**. Dependency integration is implemented as a plugin [dependency](https://docs.crawlab.cn/en/guide/plugin/plugin-dependency). - **Notifications**. Notifications feature is implemented as a plugin [notification](https://docs.crawlab.cn/en/guide/plugin/plugin-notification). #### Frontend - **Vue 3**. Migrated to latest version of frontend framework Vue 3 to support more advanced features such as composition API and TypeScript. - **UI Framework**. Built with Vue 3-based UI framework Element-Plus from Vue-Element-Admin, more flexibility and functionality. - **Advanced File Editor**. Support more advanced file editor features including drag-and-drop copying/moving files, renaming, deleting, file editing, code highlight, nav tabs, etc. - **Customizable Table**. Support more advanced built-in operations such as columns adjustment, batch operation, searching, filtering, sorting, etc. - **Nav Tabs**. Support multiple nav tabs for viewing different pages. - **Batch Creation**. Support batch creating objects including spiders, projects, schedules, etc. - **Detail Navigation**. Sidebar navigation in detail pages. - **Enhanced Dashboard**. More stats charts in home page dashboard. #### Miscellaneous - **Documentation Site**. Upgraded [documentation site](https://docs.crawlab.cn/en). - **Official Plugins**. Allow users to install [official plugins](https://docs.crawlab.cn/en/guide/plugin/) on Crawlab web UI. ================================================ FILE: core/.editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true [{*.yaml,*.yml,package.json}] indent_size = 2 indent_style = space ================================================ FILE: core/.github/workflows/test.yml ================================================ name: "Test" on: push: branches: [ main, develop ] pull_request: # The branches below must be a subset of the branches above branches: [ main, develop ] jobs: test: name: Test runs-on: ubuntu-20.04 services: mongo: image: mongo:5 ports: - 27017:27017 env: CRAWLAB_SERVER_PORT: 9999 steps: - name: Checkout repository uses: actions/checkout@v2 - uses: actions/setup-go@v3 with: go-version: '^1.22' - name: Run unit tests run: | mods=(\ "github.com/crawlab-team/crawlab/core/controllers" \ "github.com/crawlab-team/crawlab/core/models/client" \ "github.com/crawlab-team/crawlab/core/models/service" \ ) for pkg in ${mods[@]}; do go test ${pkg} done ================================================ FILE: core/.gitignore ================================================ .idea .DS_Store vendor/ tmp/ build/ dist/ *.log gen/ *.exe *.txt ================================================ FILE: core/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: core/README.md ================================================ # crawlab-core Backend core modules for Crawlab ================================================ FILE: core/apps/api_v2.go ================================================ package apps import ( "context" "errors" "github.com/apex/log" "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/utils" "github.com/gin-gonic/gin" "github.com/spf13/viper" "net" "net/http" "time" ) func init() { // set gin mode if viper.GetString("gin.mode") == "" { gin.SetMode(gin.ReleaseMode) } else { gin.SetMode(viper.GetString("gin.mode")) } } type ApiV2 struct { // dependencies interfaces.WithConfigPath // internals app *gin.Engine ln net.Listener srv *http.Server ready bool } func (app *ApiV2) Init() { // initialize middlewares _ = app.initModuleWithApp("middlewares", middlewares.InitMiddlewares) // initialize routes _ = app.initModuleWithApp("routes", controllers.InitRoutes) } func (app *ApiV2) Start() { // address host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) // http server app.srv = &http.Server{ Handler: app.app, Addr: address, } // listen var err error app.ln, err = net.Listen("tcp", address) if err != nil { panic(err) } app.ready = true // serve if err := http.Serve(app.ln, app.app); err != nil { if !errors.Is(err, http.ErrServerClosed) { log.Error("run server error:" + err.Error()) } else { log.Info("server graceful down") } } } func (app *ApiV2) Wait() { utils.DefaultWait() } func (app *ApiV2) 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()) } } func (app *ApiV2) GetGinEngine() *gin.Engine { return app.app } func (app *ApiV2) GetHttpServer() *http.Server { return app.srv } func (app *ApiV2) Ready() (ok bool) { return app.ready } func (app *ApiV2) initModuleWithApp(name string, fn func(app *gin.Engine) error) (err error) { return initModule(name, func() error { return fn(app.app) }) } func NewApiV2() *ApiV2 { api := &ApiV2{ app: gin.New(), } api.Init() return api } var apiV2 *ApiV2 func GetApiV2() *ApiV2 { if apiV2 != nil { return apiV2 } apiV2 = NewApiV2() return apiV2 } ================================================ FILE: core/apps/docker.go ================================================ package apps import ( "bufio" "fmt" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/sys_exec" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/imroc/req" "github.com/spf13/viper" "os" "os/exec" "strings" "time" ) type Docker struct { // parent parent ServerApp // dependencies interfaces.WithConfigPath // seaweedfs log fsLogFilePath string fsLogFile *os.File fsReady bool } func (app *Docker) Init() { var err error app.fsLogFile, err = os.OpenFile(app.fsLogFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.FileMode(0777)) if err != nil { trace.PrintError(err) } // replace paths if err := app.replacePaths(); err != nil { panic(err) } // start nginx go app.startNginx() // start seaweedfs go app.startSeaweedFs() } func (app *Docker) Start() { // import demo //if utils.IsDemo() && utils.InitializedDemo() { // go app.importDemo() //} } func (app *Docker) Wait() { DefaultWait() } func (app *Docker) Stop() { } func (app *Docker) GetParent() (parent ServerApp) { return app.parent } func (app *Docker) SetParent(parent ServerApp) { app.parent = parent } func (app *Docker) Ready() (ok bool) { return app.fsReady && app.parent.GetApi().Ready() } func (app *Docker) replacePaths() (err error) { // read indexHtmlPath := "/app/dist/index.html" indexHtmlBytes, err := os.ReadFile(indexHtmlPath) if err != nil { return trace.TraceError(err) } indexHtml := string(indexHtmlBytes) // replace paths baseUrl := viper.GetString("base.url") if baseUrl != "" { indexHtml = app._replacePath(indexHtml, "js", baseUrl) indexHtml = app._replacePath(indexHtml, "css", baseUrl) indexHtml = app._replacePath(indexHtml, " 0 { taskCount := int64(st.Tasks) st.AverageWaitDuration = int64(math.Round(float64(st.WaitDuration) / float64(taskCount))) st.AverageRuntimeDuration = int64(math.Round(float64(st.RuntimeDuration) / float64(taskCount))) st.AverageTotalDuration = int64(math.Round(float64(st.TotalDuration) / float64(taskCount))) } dict[st.Id] = st if !st.LastTaskId.IsZero() { taskIds = append(taskIds, st.LastTaskId) } } // task list and stats var tasks []models2.TaskV2 dictTask := map[primitive.ObjectID]models2.TaskV2{} dictTaskStat := map[primitive.ObjectID]models2.TaskStatV2{} if len(taskIds) > 0 { // task list queryTask := bson.M{ "_id": bson.M{ "$in": taskIds, }, } tasks, err = service.NewModelServiceV2[models2.TaskV2]().GetMany(queryTask, nil) if err != nil { HandleErrorInternalServerError(c, err) return } // task stats list taskStats, err := service.NewModelServiceV2[models2.TaskStatV2]().GetMany(queryTask, nil) if err != nil { HandleErrorInternalServerError(c, err) return } // cache task stats to dict for _, st := range taskStats { dictTaskStat[st.Id] = st } // cache task list to dict for _, t := range tasks { st, ok := dictTaskStat[t.Id] if ok { t.Stat = &st } dictTask[t.SpiderId] = t } } // git list var gits []models2.GitV2 if len(gitIds) > 0 && utils.IsPro() { gits, err = service.NewModelServiceV2[models2.GitV2]().GetMany(bson.M{"_id": bson.M{"$in": gitIds}}, nil) if err != nil { HandleErrorInternalServerError(c, err) return } } // cache git list to dict dictGit := map[primitive.ObjectID]models2.GitV2{} for _, g := range gits { dictGit[g.Id] = g } // iterate list again var data []models2.SpiderV2 for _, s := range spiders { // spider stat st, ok := dict[s.Id] if ok { s.Stat = &st // last task t, ok := dictTask[s.Id] if ok { s.Stat.LastTask = &t } } // git if !s.GitId.IsZero() && utils.IsPro() { g, ok := dictGit[s.GitId] if ok { s.Git = &g } } // add to list data = append(data, s) } // response HandleSuccessWithListData(c, data, total) } func PostSpider(c *gin.Context) { // bind var s models2.SpiderV2 if err := c.ShouldBindJSON(&s); err != nil { HandleErrorBadRequest(c, err) return } // user u := GetUserFromContextV2(c) // add s.SetCreated(u.Id) s.SetUpdated(u.Id) id, err := service.NewModelServiceV2[models2.SpiderV2]().InsertOne(s) if err != nil { HandleErrorInternalServerError(c, err) return } s.SetId(id) // add stat st := models2.SpiderStatV2{} st.SetId(id) st.SetCreated(u.Id) st.SetUpdated(u.Id) _, err = service.NewModelServiceV2[models2.SpiderStatV2]().InsertOne(st) if err != nil { HandleErrorInternalServerError(c, err) return } // create folder fsSvc, err := getSpiderFsSvcById(id) if err != nil { HandleErrorInternalServerError(c, err) return } err = fsSvc.CreateDir(".") if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, s) } func PutSpiderById(c *gin.Context) { id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // bind var s models2.SpiderV2 if err := c.ShouldBindJSON(&s); err != nil { HandleErrorBadRequest(c, err) return } u := GetUserFromContextV2(c) modelSvc := service.NewModelServiceV2[models2.SpiderV2]() // save s.SetUpdated(u.Id) err = modelSvc.ReplaceById(id, s) if err != nil { HandleErrorInternalServerError(c, err) return } _s, err := modelSvc.GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } s = *_s HandleSuccessWithData(c, s) } func DeleteSpiderById(c *gin.Context) { id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } if err := mongo.RunTransaction(func(context mongo2.SessionContext) (err error) { // delete spider err = service.NewModelServiceV2[models2.SpiderV2]().DeleteById(id) if err != nil { return err } // delete spider stat err = service.NewModelServiceV2[models2.SpiderStatV2]().DeleteById(id) if err != nil { return err } // related tasks tasks, err := service.NewModelServiceV2[models2.TaskV2]().GetMany(bson.M{"spider_id": id}, nil) if err != nil { return err } if len(tasks) == 0 { return nil } // task ids var taskIds []primitive.ObjectID for _, t := range tasks { taskIds = append(taskIds, t.Id) } // delete related tasks err = service.NewModelServiceV2[models2.TaskV2]().DeleteMany(bson.M{"_id": bson.M{"$in": taskIds}}) if err != nil { return err } // delete related task stats err = service.NewModelServiceV2[models2.TaskStatV2]().DeleteMany(bson.M{"_id": bson.M{"$in": taskIds}}) if err != nil { return err } // delete tasks logs wg := sync.WaitGroup{} wg.Add(len(taskIds)) for _, id := range taskIds { go func(id string) { // delete task logs logPath := filepath.Join(viper.GetString("log.path"), id) if err := os.RemoveAll(logPath); err != nil { log.Warnf("failed to remove task log directory: %s", logPath) } wg.Done() }(id.Hex()) } wg.Wait() return nil }); err != nil { HandleErrorInternalServerError(c, err) return } go func() { // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { log.Errorf("failed to get spider: %s", err.Error()) trace.PrintError(err) return } // skip spider with git if !s.GitId.IsZero() { return } // delete spider directory fsSvc, err := getSpiderFsSvcById(id) if err != nil { log.Errorf("failed to get spider fs service: %s", err.Error()) trace.PrintError(err) return } err = fsSvc.Delete(".") if err != nil { log.Errorf("failed to delete spider directory: %s", err.Error()) trace.PrintError(err) return } }() HandleSuccess(c) } func DeleteSpiderList(c *gin.Context) { var payload struct { Ids []primitive.ObjectID `json:"ids"` } if err := c.ShouldBindJSON(&payload); err != nil { HandleErrorBadRequest(c, err) return } if err := mongo.RunTransaction(func(context mongo2.SessionContext) (err error) { // delete spiders if err := service.NewModelServiceV2[models2.SpiderV2]().DeleteMany(bson.M{ "_id": bson.M{ "$in": payload.Ids, }, }); err != nil { return err } // delete spider stats if err := service.NewModelServiceV2[models2.SpiderStatV2]().DeleteMany(bson.M{ "_id": bson.M{ "$in": payload.Ids, }, }); err != nil { return err } // related tasks tasks, err := service.NewModelServiceV2[models2.TaskV2]().GetMany(bson.M{"spider_id": bson.M{"$in": payload.Ids}}, nil) if err != nil { return err } if len(tasks) == 0 { return nil } // task ids var taskIds []primitive.ObjectID for _, t := range tasks { taskIds = append(taskIds, t.Id) } // delete related tasks if err := service.NewModelServiceV2[models2.TaskV2]().DeleteMany(bson.M{"_id": bson.M{"$in": taskIds}}); err != nil { return err } // delete related task stats if err := service.NewModelServiceV2[models2.TaskStatV2]().DeleteMany(bson.M{"_id": bson.M{"$in": taskIds}}); err != nil { return err } // delete tasks logs wg := sync.WaitGroup{} wg.Add(len(taskIds)) for _, id := range taskIds { go func(id string) { // delete task logs logPath := filepath.Join(viper.GetString("log.path"), id) if err := os.RemoveAll(logPath); err != nil { log.Warnf("failed to remove task log directory: %s", logPath) } wg.Done() }(id.Hex()) } wg.Wait() return nil }); err != nil { HandleErrorInternalServerError(c, err) return } // delete spider directories go func() { wg := sync.WaitGroup{} wg.Add(len(payload.Ids)) for _, id := range payload.Ids { go func(id primitive.ObjectID) { defer wg.Done() // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { log.Errorf("failed to get spider: %s", err.Error()) trace.PrintError(err) return } // skip spider with git if !s.GitId.IsZero() { return } // delete spider directory fsSvc, err := getSpiderFsSvcById(id) if err != nil { log.Errorf("failed to get spider fs service: %s", err.Error()) trace.PrintError(err) return } err = fsSvc.Delete(".") if err != nil { log.Errorf("failed to delete spider directory: %s", err.Error()) trace.PrintError(err) return } }(id) } wg.Wait() }() HandleSuccess(c) } func GetSpiderListDir(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } GetBaseFileListDir(rootPath, c) } func GetSpiderFile(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } GetBaseFileFile(rootPath, c) } func GetSpiderFileInfo(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } GetBaseFileFileInfo(rootPath, c) } func PostSpiderSaveFile(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } PostBaseFileSaveFile(rootPath, c) } func PostSpiderSaveFiles(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } targetDirectory := c.PostForm("targetDirectory") PostBaseFileSaveFiles(filepath.Join(rootPath, targetDirectory), c) } func PostSpiderSaveDir(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } PostBaseFileSaveDir(rootPath, c) } func PostSpiderRenameFile(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } PostBaseFileRenameFile(rootPath, c) } func DeleteSpiderFile(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } DeleteBaseFileFile(rootPath, c) } func PostSpiderCopyFile(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } PostBaseFileCopyFile(rootPath, c) } func PostSpiderExport(c *gin.Context) { rootPath, err := getSpiderRootPath(c) if err != nil { HandleErrorForbidden(c, err) return } PostBaseFileExport(rootPath, c) } func PostSpiderRun(c *gin.Context) { id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // options var opts interfaces.SpiderRunOptions if err := c.ShouldBindJSON(&opts); err != nil { HandleErrorInternalServerError(c, err) return } // user if u := GetUserFromContext(c); u != nil { opts.UserId = u.GetId() } adminSvc, err := admin.GetSpiderAdminServiceV2() if err != nil { HandleErrorInternalServerError(c, err) return } // schedule taskIds, err := adminSvc.Schedule(id, &opts) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, taskIds) } func GetSpiderDataSource(c *gin.Context) { // spider id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } // data source ds, err := service.NewModelServiceV2[models2.DatabaseV2]().GetById(s.DataSourceId) if err != nil { if err.Error() == mongo2.ErrNoDocuments.Error() { HandleSuccess(c) return } HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, ds) } func PostSpiderDataSource(c *gin.Context) { // spider id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // data source id dsId, err := primitive.ObjectIDFromHex(c.Param("ds_id")) if err != nil { HandleErrorBadRequest(c, err) return } // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } // data source if !dsId.IsZero() { _, err = service.NewModelServiceV2[models2.DatabaseV2]().GetById(dsId) if err != nil { HandleErrorInternalServerError(c, err) return } } // save data source id u := GetUserFromContextV2(c) s.DataSourceId = dsId s.SetUpdatedBy(u.Id) _, err = service.NewModelServiceV2[models2.SpiderV2]().InsertOne(*s) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccess(c) } func getSpiderFsSvc(s *models2.SpiderV2) (svc interfaces.FsServiceV2, err error) { workspacePath := viper.GetString("workspace") fsSvc := fs.NewFsServiceV2(filepath.Join(workspacePath, s.Id.Hex())) return fsSvc, nil } func getSpiderFsSvcById(id primitive.ObjectID) (svc interfaces.FsServiceV2, err error) { s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { log.Errorf("failed to get spider: %s", err.Error()) trace.PrintError(err) return nil, err } return getSpiderFsSvc(s) } func getSpiderRootPath(c *gin.Context) (rootPath string, err error) { // spider id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { return "", err } // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { return "", err } // check git permission if !utils.IsPro() && !s.GitId.IsZero() { return "", errors.New("git is not allowed in the community version") } // if git id is zero, return spider id as root path if s.GitId.IsZero() { return id.Hex(), nil } return filepath.Join(s.GitId.Hex(), s.GitRootPath), nil } ================================================ FILE: core/controllers/spider_v2_test.go ================================================ package controllers_test import ( "bytes" "encoding/json" "github.com/crawlab-team/crawlab/core/controllers" "github.com/crawlab-team/crawlab/core/middlewares" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "net/http" "net/http/httptest" "testing" ) func TestCreateSpider(t *testing.T) { SetupTestDB() defer CleanupTestDB() gin.SetMode(gin.TestMode) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.POST("/spiders", controllers.PostSpider) payload := models.SpiderV2{ Name: "Test Spider", ColName: "test_spiders", } jsonValue, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "/spiders", bytes.NewBuffer(jsonValue)) req.Header.Set("Authorization", TestToken) resp := httptest.NewRecorder() router.ServeHTTP(resp, req) assert.Equal(t, http.StatusOK, resp.Code) var response controllers.Response[models.SpiderV2] err := json.Unmarshal(resp.Body.Bytes(), &response) require.Nil(t, err) assert.False(t, response.Data.Id.IsZero()) assert.Equal(t, payload.Name, response.Data.Name) assert.False(t, response.Data.ColId.IsZero()) } func TestGetSpiderById(t *testing.T) { SetupTestDB() defer CleanupTestDB() gin.SetMode(gin.TestMode) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.GET("/spiders/:id", controllers.GetSpiderById) model := models.SpiderV2{ Name: "Test Spider", ColName: "test_spiders", } id, err := service.NewModelServiceV2[models.SpiderV2]().InsertOne(model) require.Nil(t, err) ts := models.SpiderStatV2{} ts.SetId(id) _, err = service.NewModelServiceV2[models.SpiderStatV2]().InsertOne(ts) require.Nil(t, err) req, _ := http.NewRequest("GET", "/spiders/"+id.Hex(), nil) req.Header.Set("Authorization", TestToken) resp := httptest.NewRecorder() router.ServeHTTP(resp, req) assert.Equal(t, http.StatusOK, resp.Code) var response controllers.Response[models.SpiderV2] err = json.Unmarshal(resp.Body.Bytes(), &response) require.Nil(t, err) assert.Equal(t, model.Name, response.Data.Name) } func TestUpdateSpiderById(t *testing.T) { SetupTestDB() defer CleanupTestDB() gin.SetMode(gin.TestMode) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.PUT("/spiders/:id", controllers.PutSpiderById) model := models.SpiderV2{ Name: "Test Spider", ColName: "test_spiders", } id, err := service.NewModelServiceV2[models.SpiderV2]().InsertOne(model) require.Nil(t, err) ts := models.SpiderStatV2{} ts.SetId(id) _, err = service.NewModelServiceV2[models.SpiderStatV2]().InsertOne(ts) require.Nil(t, err) spiderId := id.Hex() payload := models.SpiderV2{ Name: "Updated Spider", ColName: "test_spider", } payload.SetId(id) jsonValue, _ := json.Marshal(payload) req, _ := http.NewRequest("PUT", "/spiders/"+spiderId, bytes.NewBuffer(jsonValue)) req.Header.Set("Authorization", TestToken) resp := httptest.NewRecorder() router.ServeHTTP(resp, req) assert.Equal(t, http.StatusOK, resp.Code) var response controllers.Response[models.SpiderV2] err = json.Unmarshal(resp.Body.Bytes(), &response) require.Nil(t, err) assert.Equal(t, payload.Name, response.Data.Name) svc := service.NewModelServiceV2[models.SpiderV2]() resModel, err := svc.GetById(id) require.Nil(t, err) assert.Equal(t, payload.Name, resModel.Name) } func TestDeleteSpiderById(t *testing.T) { SetupTestDB() defer CleanupTestDB() gin.SetMode(gin.TestMode) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.DELETE("/spiders/:id", controllers.DeleteSpiderById) model := models.SpiderV2{ Name: "Test Spider", ColName: "test_spiders", } id, err := service.NewModelServiceV2[models.SpiderV2]().InsertOne(model) require.Nil(t, err) ts := models.SpiderStatV2{} ts.SetId(id) _, err = service.NewModelServiceV2[models.SpiderStatV2]().InsertOne(ts) require.Nil(t, err) task := models.TaskV2{} task.SpiderId = id taskId, err := service.NewModelServiceV2[models.TaskV2]().InsertOne(task) require.Nil(t, err) taskStat := models.TaskStatV2{} taskStat.SetId(taskId) _, err = service.NewModelServiceV2[models.TaskStatV2]().InsertOne(taskStat) require.Nil(t, err) req, _ := http.NewRequest("DELETE", "/spiders/"+id.Hex(), nil) req.Header.Set("Authorization", TestToken) resp := httptest.NewRecorder() router.ServeHTTP(resp, req) assert.Equal(t, http.StatusOK, resp.Code) _, err = service.NewModelServiceV2[models.SpiderV2]().GetById(id) assert.NotNil(t, err) _, err = service.NewModelServiceV2[models.SpiderStatV2]().GetById(id) assert.NotNil(t, err) taskCount, err := service.NewModelServiceV2[models.TaskV2]().Count(bson.M{"spider_id": id}) require.Nil(t, err) assert.Equal(t, 0, taskCount) taskStatCount, err := service.NewModelServiceV2[models.TaskStatV2]().Count(bson.M{"_id": taskId}) require.Nil(t, err) assert.Equal(t, 0, taskStatCount) } func TestDeleteSpiderList(t *testing.T) { SetupTestDB() defer CleanupTestDB() gin.SetMode(gin.TestMode) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.DELETE("/spiders", controllers.DeleteSpiderList) modelList := []models.SpiderV2{ { Name: "Test Name 1", ColName: "test_spiders", }, { Name: "Test Name 2", ColName: "test_spiders", }, } var ids []primitive.ObjectID var taskIds []primitive.ObjectID for _, model := range modelList { id, err := service.NewModelServiceV2[models.SpiderV2]().InsertOne(model) require.Nil(t, err) ts := models.SpiderStatV2{} ts.SetId(id) _, err = service.NewModelServiceV2[models.SpiderStatV2]().InsertOne(ts) require.Nil(t, err) task := models.TaskV2{} task.SpiderId = id taskId, err := service.NewModelServiceV2[models.TaskV2]().InsertOne(task) require.Nil(t, err) taskStat := models.TaskStatV2{} taskStat.SetId(taskId) _, err = service.NewModelServiceV2[models.TaskStatV2]().InsertOne(taskStat) require.Nil(t, err) ids = append(ids, id) taskIds = append(taskIds, taskId) } payload := struct { Ids []primitive.ObjectID `json:"ids"` }{ Ids: ids, } jsonValue, _ := json.Marshal(payload) req, _ := http.NewRequest("DELETE", "/spiders", bytes.NewBuffer(jsonValue)) req.Header.Set("Authorization", TestToken) resp := httptest.NewRecorder() router.ServeHTTP(resp, req) assert.Equal(t, http.StatusOK, resp.Code) spiderCount, err := service.NewModelServiceV2[models.SpiderV2]().Count(bson.M{"_id": bson.M{"$in": ids}}) require.Nil(t, err) assert.Equal(t, 0, spiderCount) spiderStatCount, err := service.NewModelServiceV2[models.SpiderStatV2]().Count(bson.M{"_id": bson.M{"$in": ids}}) require.Nil(t, err) assert.Equal(t, 0, spiderStatCount) taskCount, err := service.NewModelServiceV2[models.TaskV2]().Count(bson.M{"_id": bson.M{"$in": taskIds}}) require.Nil(t, err) assert.Equal(t, 0, taskCount) taskStatCount, err := service.NewModelServiceV2[models.TaskStatV2]().Count(bson.M{"_id": bson.M{"$in": taskIds}}) require.Nil(t, err) assert.Equal(t, 0, taskStatCount) } ================================================ FILE: core/controllers/stats_v2.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/stats" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "time" ) var statsDefaultQuery = bson.M{ "create_ts": bson.M{ "$gte": time.Now().Add(-30 * 24 * time.Hour), }, } func GetStatsOverview(c *gin.Context) { data, err := stats.GetStatsService().GetOverviewStats(statsDefaultQuery) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, data) } func GetStatsDaily(c *gin.Context) { data, err := stats.GetStatsService().GetDailyStats(statsDefaultQuery) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, data) } func GetStatsTasks(c *gin.Context) { data, err := stats.GetStatsService().GetTaskStats(statsDefaultQuery) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, data) } ================================================ FILE: core/controllers/sync_v2.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "github.com/spf13/viper" "net/http" "path/filepath" ) func GetSyncScan(c *gin.Context) { id := c.Param("id") path := c.Query("path") workspacePath := viper.GetString("workspace") dirPath := filepath.Join(workspacePath, id, path) files, err := utils.ScanDirectory(dirPath) if err != nil { HandleErrorInternalServerError(c, err) return } c.AbortWithStatusJSON(http.StatusOK, files) } func GetSyncDownload(c *gin.Context) { id := c.Param("id") path := c.Query("path") workspacePath := viper.GetString("workspace") filePath := filepath.Join(workspacePath, id, path) c.File(filePath) } ================================================ FILE: core/controllers/system_info_v2.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/entity" "github.com/gin-gonic/gin" "github.com/spf13/viper" ) func GetSystemInfo(c *gin.Context) { info := &entity.SystemInfo{ Edition: viper.GetString("edition"), Version: viper.GetString("version"), } HandleSuccessWithData(c, info) } ================================================ FILE: core/controllers/task_v2.go ================================================ package controllers import ( "errors" log2 "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/result" "github.com/crawlab-team/crawlab/core/spider/admin" "github.com/crawlab-team/crawlab/core/task/log" "github.com/crawlab-team/crawlab/core/task/scheduler" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/db/mongo" "github.com/gin-gonic/gin" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "os" "path/filepath" "strings" "sync" ) func GetTaskById(c *gin.Context) { // id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // task t, err := service.NewModelServiceV2[models.TaskV2]().GetById(id) if errors.Is(err, mongo2.ErrNoDocuments) { HandleErrorNotFound(c, err) return } if err != nil { HandleErrorInternalServerError(c, err) return } // spider t.Spider, _ = service.NewModelServiceV2[models.SpiderV2]().GetById(t.SpiderId) // skip if task status is pending if t.Status == constants.TaskStatusPending { HandleSuccessWithData(c, t) return } // task stat t.Stat, _ = service.NewModelServiceV2[models.TaskStatV2]().GetById(id) HandleSuccessWithData(c, t) } func GetTaskList(c *gin.Context) { withStats := c.Query("stats") if withStats == "" { NewControllerV2[models.TaskV2]().GetList(c) return } // params pagination := MustGetPagination(c) query := MustGetFilterQuery(c) sort := MustGetSortOption(c) // get tasks tasks, err := service.NewModelServiceV2[models.TaskV2]().GetMany(query, &mongo.FindOptions{ Sort: sort, Skip: pagination.Size * (pagination.Page - 1), Limit: pagination.Size, }) if err != nil { if errors.Is(err, mongo2.ErrNoDocuments) { HandleErrorNotFound(c, err) } else { HandleErrorInternalServerError(c, err) } return } // check empty list if len(tasks) == 0 { HandleSuccessWithListData(c, nil, 0) return } // ids var taskIds []primitive.ObjectID var spiderIds []primitive.ObjectID for _, t := range tasks { taskIds = append(taskIds, t.Id) spiderIds = append(spiderIds, t.SpiderId) } // total count total, err := service.NewModelServiceV2[models.TaskV2]().Count(query) if err != nil { HandleErrorInternalServerError(c, err) return } // stat list stats, err := service.NewModelServiceV2[models.TaskStatV2]().GetMany(bson.M{ "_id": bson.M{ "$in": taskIds, }, }, nil) if err != nil { HandleErrorInternalServerError(c, err) return } // cache stat list to dict statsDict := map[primitive.ObjectID]models.TaskStatV2{} for _, s := range stats { statsDict[s.Id] = s } // spider list spiders, err := service.NewModelServiceV2[models.SpiderV2]().GetMany(bson.M{ "_id": bson.M{ "$in": spiderIds, }, }, nil) if err != nil { HandleErrorInternalServerError(c, err) return } // cache spider list to dict spiderDict := map[primitive.ObjectID]models.SpiderV2{} for _, s := range spiders { spiderDict[s.Id] = s } // iterate list again for i, t := range tasks { // task stat ts, ok := statsDict[t.Id] if ok { tasks[i].Stat = &ts } // spider s, ok := spiderDict[t.SpiderId] if ok { tasks[i].Spider = &s } } // response HandleSuccessWithListData(c, tasks, total) } func DeleteTaskById(c *gin.Context) { id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // delete in db if err := mongo.RunTransaction(func(context mongo2.SessionContext) (err error) { // delete task _, err = service.NewModelServiceV2[models.TaskV2]().GetById(id) if err != nil { return err } err = service.NewModelServiceV2[models.TaskV2]().DeleteById(id) if err != nil { return err } // delete task stat _, err = service.NewModelServiceV2[models.TaskStatV2]().GetById(id) if err != nil { log2.Warnf("delete task stat error: %s", err.Error()) return nil } err = service.NewModelServiceV2[models.TaskStatV2]().DeleteById(id) if err != nil { log2.Warnf("delete task stat error: %s", err.Error()) return nil } return nil }); err != nil { HandleErrorInternalServerError(c, err) return } // delete task logs logPath := filepath.Join(viper.GetString("log.path"), id.Hex()) if err := os.RemoveAll(logPath); err != nil { log2.Warnf("failed to remove task log directory: %s", logPath) } HandleSuccess(c) } func DeleteList(c *gin.Context) { var payload struct { Ids []primitive.ObjectID `json:"ids"` } if err := c.ShouldBindJSON(&payload); err != nil { HandleErrorBadRequest(c, err) return } if err := mongo.RunTransaction(func(context mongo2.SessionContext) error { // delete tasks if err := service.NewModelServiceV2[models.TaskV2]().DeleteMany(bson.M{ "_id": bson.M{ "$in": payload.Ids, }, }); err != nil { return err } // delete task stats if err := service.NewModelServiceV2[models.TaskV2]().DeleteMany(bson.M{ "_id": bson.M{ "$in": payload.Ids, }, }); err != nil { log2.Warnf("delete task stat error: %s", err.Error()) return nil } return nil }); err != nil { HandleErrorInternalServerError(c, err) return } // delete tasks logs wg := sync.WaitGroup{} wg.Add(len(payload.Ids)) for _, id := range payload.Ids { go func(id string) { // delete task logs logPath := filepath.Join(viper.GetString("log.path"), id) if err := os.RemoveAll(logPath); err != nil { log2.Warnf("failed to remove task log directory: %s", logPath) } wg.Done() }(id.Hex()) } wg.Wait() HandleSuccess(c) } func PostTaskRun(c *gin.Context) { // task var t models.TaskV2 if err := c.ShouldBindJSON(&t); err != nil { HandleErrorBadRequest(c, err) return } // validate spider id if t.SpiderId.IsZero() { HandleErrorBadRequest(c, errors.New("spider id is required")) return } // spider s, err := service.NewModelServiceV2[models.SpiderV2]().GetById(t.SpiderId) if err != nil { HandleErrorInternalServerError(c, err) return } // options opts := &interfaces.SpiderRunOptions{ Mode: t.Mode, NodeIds: t.NodeIds, Cmd: t.Cmd, Param: t.Param, Priority: t.Priority, } // user if u := GetUserFromContextV2(c); u != nil { opts.UserId = u.Id } // run adminSvc, err := admin.GetSpiderAdminServiceV2() if err != nil { HandleErrorInternalServerError(c, err) return } taskIds, err := adminSvc.Schedule(s.Id, opts) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, taskIds) } func PostTaskRestart(c *gin.Context) { // id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // task t, err := service.NewModelServiceV2[models.TaskV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } // options opts := &interfaces.SpiderRunOptions{ Mode: t.Mode, NodeIds: t.NodeIds, Cmd: t.Cmd, Param: t.Param, Priority: t.Priority, } // user if u := GetUserFromContextV2(c); u != nil { opts.UserId = u.Id } // run adminSvc, err := admin.GetSpiderAdminServiceV2() if err != nil { HandleErrorInternalServerError(c, err) return } taskIds, err := adminSvc.Schedule(t.SpiderId, opts) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, taskIds) } func PostTaskCancel(c *gin.Context) { // id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // task t, err := service.NewModelServiceV2[models.TaskV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } // validate if !utils.IsCancellable(t.Status) { HandleErrorInternalServerError(c, errors.New("task is not cancellable")) return } u := GetUserFromContextV2(c) // cancel schedulerSvc, err := scheduler.GetTaskSchedulerServiceV2() if err != nil { HandleErrorInternalServerError(c, err) return } if err := schedulerSvc.Cancel(id, u.Id); err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccess(c) } func GetTaskLogs(c *gin.Context) { // id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // pagination p, err := GetPagination(c) if err != nil { HandleErrorBadRequest(c, err) return } // logs logDriver, err := log.GetFileLogDriver() if err != nil { HandleErrorInternalServerError(c, err) return } logs, err := logDriver.Find(id.Hex(), "", (p.Page-1)*p.Size, p.Size) if err != nil { if strings.HasSuffix(err.Error(), "Status:404 Not Found") { HandleSuccess(c) return } HandleErrorInternalServerError(c, err) return } total, err := logDriver.Count(id.Hex(), "") if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithListData(c, logs, total) } func GetTaskData(c *gin.Context) { // id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // pagination p, err := GetPagination(c) if err != nil { HandleErrorBadRequest(c, err) return } // task t, err := service.NewModelServiceV2[models.TaskV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } // result service resultSvc, err := result.GetResultService(t.SpiderId) if err != nil { HandleErrorInternalServerError(c, err) return } // query query := generic.ListQuery{ generic.ListQueryCondition{ Key: constants.TaskKey, Op: generic.OpEqual, Value: t.Id, }, } // list data, err := resultSvc.List(query, &generic.ListOptions{ Skip: (p.Page - 1) * p.Size, Limit: p.Size, Sort: []generic.ListSort{{"_id", generic.SortDirectionDesc}}, }) if err != nil { HandleErrorInternalServerError(c, err) return } // total total, err := resultSvc.Count(query) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithListData(c, data, total) } ================================================ FILE: core/controllers/token_v2.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/user" "github.com/gin-gonic/gin" ) func PostToken(c *gin.Context) { var t models.TokenV2 if err := c.ShouldBindJSON(&t); err != nil { HandleErrorBadRequest(c, err) return } svc, err := user.GetUserServiceV2() if err != nil { HandleErrorInternalServerError(c, err) return } u := GetUserFromContextV2(c) t.SetCreated(u.Id) t.SetUpdated(u.Id) t.Token, err = svc.MakeToken(u) if err != nil { HandleErrorInternalServerError(c, err) return } _, err = service.NewModelServiceV2[models.TokenV2]().InsertOne(t) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccess(c) } ================================================ FILE: core/controllers/user_v2.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson/primitive" ) func PostUser(c *gin.Context) { var payload struct { Username string `json:"username"` Password string `json:"password"` Role string `json:"role"` Email string `json:"email"` } if err := c.ShouldBindJSON(&payload); err != nil { HandleErrorBadRequest(c, err) return } u := GetUserFromContextV2(c) model := models.UserV2{ Username: payload.Username, Password: utils.EncryptMd5(payload.Password), Role: payload.Role, Email: payload.Email, } model.SetCreated(u.Id) model.SetUpdated(u.Id) id, err := service.NewModelServiceV2[models.UserV2]().InsertOne(model) if err != nil { HandleErrorInternalServerError(c, err) return } result, err := service.NewModelServiceV2[models.UserV2]().GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, result) } func PostUserChangePassword(c *gin.Context) { // get id id, err := primitive.ObjectIDFromHex(c.Param("id")) if err != nil { HandleErrorBadRequest(c, err) return } // get payload var payload struct { Password string `json:"password"` } if err := c.ShouldBindJSON(&payload); err != nil { HandleErrorBadRequest(c, err) return } // get user u := GetUserFromContextV2(c) modelSvc := service.NewModelServiceV2[models.UserV2]() // update password user, err := modelSvc.GetById(id) if err != nil { HandleErrorInternalServerError(c, err) return } user.SetUpdated(u.Id) user.Password = utils.EncryptMd5(payload.Password) if err := modelSvc.ReplaceById(user.Id, *user); err != nil { HandleErrorInternalServerError(c, err) return } // handle success HandleSuccess(c) } func GetUserMe(c *gin.Context) { u := GetUserFromContextV2(c) _u, err := service.NewModelServiceV2[models.UserV2]().GetById(u.Id) if err != nil { HandleErrorInternalServerError(c, err) return } HandleSuccessWithData(c, _u) } func PutUserById(c *gin.Context) { // get payload var user models.UserV2 if err := c.ShouldBindJSON(&user); err != nil { HandleErrorBadRequest(c, err) return } // get user u := GetUserFromContextV2(c) modelSvc := service.NewModelServiceV2[models.UserV2]() // update user userDb, err := modelSvc.GetById(u.Id) if err != nil { HandleErrorInternalServerError(c, err) return } user.Password = userDb.Password user.SetUpdated(u.Id) if user.Id.IsZero() { user.Id = u.Id } if err := modelSvc.ReplaceById(u.Id, user); err != nil { HandleErrorInternalServerError(c, err) return } // handle success HandleSuccess(c) } ================================================ FILE: core/controllers/user_v2_test.go ================================================ package controllers_test import ( "github.com/crawlab-team/crawlab/core/controllers" "github.com/crawlab-team/crawlab/core/middlewares" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "strings" "testing" ) func TestPostUserChangePassword_Success(t *testing.T) { SetupTestDB() defer CleanupTestDB() modelSvc := service.NewModelServiceV2[models.UserV2]() u := models.UserV2{} id, err := modelSvc.InsertOne(u) assert.Nil(t, err) u.SetId(id) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.POST("/users/:id/change-password", controllers.PostUserChangePassword) password := "newPassword" reqBody := strings.NewReader(`{"password":"` + password + `"}`) req, _ := http.NewRequest(http.MethodPost, "/users/"+id.Hex()+"/change-password", reqBody) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", TestToken) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } func TestGetUserMe_Success(t *testing.T) { SetupTestDB() defer CleanupTestDB() modelSvc := service.NewModelServiceV2[models.UserV2]() u := models.UserV2{} id, err := modelSvc.InsertOne(u) assert.Nil(t, err) u.SetId(id) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.GET("/users/me", controllers.GetUserMe) req, _ := http.NewRequest(http.MethodGet, "/users/me", nil) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", TestToken) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } func TestPutUserById_Success(t *testing.T) { SetupTestDB() defer CleanupTestDB() modelSvc := service.NewModelServiceV2[models.UserV2]() u := models.UserV2{} id, err := modelSvc.InsertOne(u) assert.Nil(t, err) u.SetId(id) router := gin.Default() router.Use(middlewares.AuthorizationMiddlewareV2()) router.PUT("/users/me", controllers.PutUserById) reqBody := strings.NewReader(`{"id":"` + id.Hex() + `","username":"newUsername","email":"newEmail@test.com"}`) req, _ := http.NewRequest(http.MethodPut, "/users/me", reqBody) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", TestToken) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } ================================================ FILE: core/controllers/utils_context.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/gin-gonic/gin" ) func GetUserFromContext(c *gin.Context) (u interfaces.User) { value, ok := c.Get(constants.UserContextKey) if !ok { return nil } u, ok = value.(interfaces.User) if !ok { return nil } return u } func GetUserFromContextV2(c *gin.Context) (u *models.UserV2) { value, ok := c.Get(constants.UserContextKey) if !ok { return nil } u, ok = value.(*models.UserV2) if !ok { return nil } return u } ================================================ FILE: core/controllers/utils_filter.go ================================================ package controllers import ( "encoding/json" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "reflect" "strings" ) // GetFilter Get entity.Filter from gin.Context func GetFilter(c *gin.Context) (f *entity.Filter, err error) { // bind condStr := c.Query(constants.FilterQueryFieldConditions) var conditions []*entity.Condition if err := json.Unmarshal([]byte(condStr), &conditions); err != nil { return nil, err } // attempt to convert object id for i, cond := range conditions { v := reflect.ValueOf(cond.Value) switch v.Kind() { case reflect.String: item := cond.Value.(string) id, err := primitive.ObjectIDFromHex(item) if err == nil { conditions[i].Value = id } else { conditions[i].Value = item } case reflect.Slice, reflect.Array: var items []interface{} for i := 0; i < v.Len(); i++ { vItem := v.Index(i) item := vItem.Interface() // string stringItem, ok := item.(string) if ok { id, err := primitive.ObjectIDFromHex(stringItem) if err == nil { items = append(items, id) } else { items = append(items, stringItem) } continue } // default items = append(items, item) } conditions[i].Value = items } } return &entity.Filter{ IsOr: false, Conditions: conditions, }, nil } // GetFilterQuery Get bson.M from gin.Context func GetFilterQuery(c *gin.Context) (q bson.M, err error) { f, err := GetFilter(c) if err != nil { return nil, err } if f == nil { return nil, nil } // TODO: implement logic OR return utils.FilterToQuery(f) } func MustGetFilterQuery(c *gin.Context) (q bson.M) { q, err := GetFilterQuery(c) if err != nil { return nil } return q } // GetFilterAll Get all from gin.Context func GetFilterAll(c *gin.Context) (res bool, err error) { resStr := c.Query(constants.FilterQueryFieldAll) switch strings.ToUpper(resStr) { case "1": return true, nil case "0": return false, nil case "Y": return true, nil case "N": return false, nil case "T": return true, nil case "F": return false, nil case "TRUE": return true, nil case "FALSE": return false, nil default: return false, errors.ErrorFilterInvalidOperation } } func MustGetFilterAll(c *gin.Context) (res bool) { res, err := GetFilterAll(c) if err != nil { return false } return res } ================================================ FILE: core/controllers/utils_http.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/trace" "github.com/gin-gonic/gin" "net/http" ) func handleError(statusCode int, c *gin.Context, err error, print bool) { if print { trace.PrintError(err) } c.AbortWithStatusJSON(statusCode, entity.Response{ Status: constants.HttpResponseStatusOk, Message: constants.HttpResponseMessageError, Error: err.Error(), }) } func HandleError(statusCode int, c *gin.Context, err error) { handleError(statusCode, c, err, true) } func HandleErrorNoPrint(statusCode int, c *gin.Context, err error) { handleError(statusCode, c, err, false) } func HandleErrorBadRequest(c *gin.Context, err error) { HandleError(http.StatusBadRequest, c, err) } func HandleErrorForbidden(c *gin.Context, err error) { HandleError(http.StatusForbidden, c, err) } func HandleErrorUnauthorized(c *gin.Context, err error) { HandleError(http.StatusUnauthorized, c, err) } func HandleErrorNotFound(c *gin.Context, err error) { HandleError(http.StatusNotFound, c, err) } func HandleErrorNotFoundNoPrint(c *gin.Context, err error) { HandleErrorNoPrint(http.StatusNotFound, c, err) } func HandleErrorInternalServerError(c *gin.Context, err error) { HandleError(http.StatusInternalServerError, c, err) } func HandleSuccess(c *gin.Context) { c.AbortWithStatusJSON(http.StatusOK, entity.Response{ Status: constants.HttpResponseStatusOk, Message: constants.HttpResponseMessageSuccess, }) } func HandleSuccessWithData(c *gin.Context, data interface{}) { c.AbortWithStatusJSON(http.StatusOK, entity.Response{ Status: constants.HttpResponseStatusOk, Message: constants.HttpResponseMessageSuccess, Data: data, }) } func HandleSuccessWithListData(c *gin.Context, data interface{}, total int) { c.AbortWithStatusJSON(http.StatusOK, entity.ListResponse{ Status: constants.HttpResponseStatusOk, Message: constants.HttpResponseMessageSuccess, Data: data, Total: total, }) } ================================================ FILE: core/controllers/utils_pagination.go ================================================ package controllers import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/gin-gonic/gin" ) func GetDefaultPagination() (p *entity.Pagination) { return &entity.Pagination{ Page: constants.PaginationDefaultPage, Size: constants.PaginationDefaultSize, } } func GetPagination(c *gin.Context) (p *entity.Pagination, err error) { var _p entity.Pagination if err := c.ShouldBindQuery(&_p); err != nil { return GetDefaultPagination(), err } return &_p, nil } func MustGetPagination(c *gin.Context) (p *entity.Pagination) { p, err := GetPagination(c) if err != nil || p == nil { return GetDefaultPagination() } return p } ================================================ FILE: core/controllers/utils_sort.go ================================================ package controllers import ( "encoding/json" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" ) // GetSorts Get entity.Sort from gin.Context func GetSorts(c *gin.Context) (sorts []entity.Sort, err error) { // bind sortStr := c.Query(constants.SortQueryField) if err := json.Unmarshal([]byte(sortStr), &sorts); err != nil { return nil, err } return sorts, nil } // GetSortsOption Get entity.Sort from gin.Context func GetSortsOption(c *gin.Context) (sort bson.D, err error) { sorts, err := GetSorts(c) if err != nil { return nil, err } if sorts == nil || len(sorts) == 0 { return bson.D{{"_id", -1}}, nil } return SortsToOption(sorts) } func MustGetSortOption(c *gin.Context) (sort bson.D) { sort, err := GetSortsOption(c) if err != nil { return nil } return sort } // SortsToOption Translate entity.Sort to bson.D func SortsToOption(sorts []entity.Sort) (sort bson.D, err error) { sort = bson.D{} for _, s := range sorts { switch s.Direction { case constants.ASCENDING: sort = append(sort, bson.E{Key: s.Key, Value: 1}) case constants.DESCENDING: sort = append(sort, bson.E{Key: s.Key, Value: -1}) } } if len(sort) == 0 { sort = bson.D{{"_id", -1}} } return sort, nil } ================================================ FILE: core/controllers/ws_writer.go ================================================ package controllers import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/trace" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "io" http2 "net/http" ) type WsWriter struct { io.Writer io.Closer conn *websocket.Conn } func (w *WsWriter) Write(data []byte) (n int, err error) { log.Infof("websocket write: %s", string(data)) err = w.conn.WriteMessage(websocket.TextMessage, data) if err != nil { return 0, err } return len(data), nil } func (w *WsWriter) Close() (err error) { return w.conn.Close() } func (w *WsWriter) CloseWithText(text string) { _ = w.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, text)) } func (w *WsWriter) CloseWithError(err error) { _ = w.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseInternalServerErr, err.Error())) } func NewWsWriter(c *gin.Context) (writer *WsWriter, err error) { upgrader := websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http2.Request) bool { return true }, } conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { log.Errorf("websocket open connection error: %v", err) trace.PrintError(err) } return &WsWriter{ conn: conn, }, nil } ================================================ FILE: core/data/colors.go ================================================ package data const ColorsDataText = `[ { "name": "Absolute Zero", "hex": "#0048BA" }, { "name": "Acid Green", "hex": "#B0BF1A" }, { "name": "Aero", "hex": "#7CB9E8" }, { "name": "Aero Blue", "hex": "#C9FFE5" }, { "name": "African Violet", "hex": "#B284BE" }, { "name": "Air Force Blue (RAF)", "hex": "#5D8AA8" }, { "name": "Air Force Blue (USAF)", "hex": "#00308F" }, { "name": "Air Superiority Blue", "hex": "#72A0C1" }, { "name": "Alabama Crimson", "hex": "#AF002A" }, { "name": "Alabaster", "hex": "#F2F0E6" }, { "name": "Alice Blue", "hex": "#F0F8FF" }, { "name": "Alien Armpit", "hex": "#84DE02" }, { "name": "Alizarin Crimson", "hex": "#E32636" }, { "name": "Alloy Orange", "hex": "#C46210" }, { "name": "Almond", "hex": "#EFDECD" }, { "name": "Amaranth", "hex": "#E52B50" }, { "name": "Amaranth Deep Purple", "hex": "#9F2B68" }, { "name": "Amaranth Pink", "hex": "#F19CBB" }, { "name": "Amaranth Purple", "hex": "#AB274F" }, { "name": "Amaranth Red", "hex": "#D3212D" }, { "name": "Amazon Store", "hex": "#3B7A57" }, { "name": "Amazonite", "hex": "#00C4B0" }, { "name": "Amber", "hex": "#FFBF00" }, { "name": "Amber (SAE/ECE)", "hex": "#FF7E00" }, { "name": "American Rose", "hex": "#FF033E" }, { "name": "Amethyst", "hex": "#9966CC" }, { "name": "Android Green", "hex": "#A4C639" }, { "name": "Anti-Flash White", "hex": "#F2F3F4" }, { "name": "Antique Brass", "hex": "#CD9575" }, { "name": "Antique Bronze", "hex": "#665D1E" }, { "name": "Antique Fuchsia", "hex": "#915C83" }, { "name": "Antique Ruby", "hex": "#841B2D" }, { "name": "Antique White", "hex": "#FAEBD7" }, { "name": "Ao (English)", "hex": "#008000" }, { "name": "Apple Green", "hex": "#8DB600" }, { "name": "Apricot", "hex": "#FBCEB1" }, { "name": "Aqua", "hex": "#00FFFF" }, { "name": "Aquamarine", "hex": "#7FFFD4" }, { "name": "Arctic Lime", "hex": "#D0FF14" }, { "name": "Army Green", "hex": "#4B5320" }, { "name": "Arsenic", "hex": "#3B444B" }, { "name": "Artichoke", "hex": "#8F9779" }, { "name": "Arylide Yellow", "hex": "#E9D66B" }, { "name": "Ash Gray", "hex": "#B2BEB5" }, { "name": "Asparagus", "hex": "#87A96B" }, { "name": "Atomic Tangerine", "hex": "#FF9966" }, { "name": "Auburn", "hex": "#A52A2A" }, { "name": "Aureolin", "hex": "#FDEE00" }, { "name": "AuroMetalSaurus", "hex": "#6E7F80" }, { "name": "Avocado", "hex": "#568203" }, { "name": "Awesome", "hex": "#FF2052" }, { "name": "Aztec Gold", "hex": "#C39953" }, { "name": "Azure", "hex": "#007FFF" }, { "name": "Azure (Web Color)", "hex": "#F0FFFF" }, { "name": "Azure Mist", "hex": "#F0FFFF" }, { "name": "Azureish White", "hex": "#DBE9F4" }, { "name": "Baby Blue", "hex": "#89CFF0" }, { "name": "Baby Blue Eyes", "hex": "#A1CAF1" }, { "name": "Baby Pink", "hex": "#F4C2C2" }, { "name": "Baby Powder", "hex": "#FEFEFA" }, { "name": "Baker-Miller Pink", "hex": "#FF91AF" }, { "name": "Ball Blue", "hex": "#21ABCD" }, { "name": "Banana Mania", "hex": "#FAE7B5" }, { "name": "Banana Yellow", "hex": "#FFE135" }, { "name": "Bangladesh Green", "hex": "#006A4E" }, { "name": "Barbie Pink", "hex": "#E0218A" }, { "name": "Barn Red", "hex": "#7C0A02" }, { "name": "Battery Charged Blue", "hex": "#1DACD6" }, { "name": "Battleship Grey", "hex": "#848482" }, { "name": "Bazaar", "hex": "#98777B" }, { "name": "Beau Blue", "hex": "#BCD4E6" }, { "name": "Beaver", "hex": "#9F8170" }, { "name": "Begonia", "hex": "#FA6E79" }, { "name": "Beige", "hex": "#F5F5DC" }, { "name": "B'dazzled Blue", "hex": "#2E5894" }, { "name": "Big Dip O'ruby", "hex": "#9C2542" }, { "name": "Big Foot Feet", "hex": "#E88E5A" }, { "name": "Bisque", "hex": "#FFE4C4" }, { "name": "Bistre", "hex": "#3D2B1F" }, { "name": "Bistre Brown", "hex": "#967117" }, { "name": "Bitter Lemon", "hex": "#CAE00D" }, { "name": "Bitter Lime", "hex": "#BFFF00" }, { "name": "Bittersweet", "hex": "#FE6F5E" }, { "name": "Bittersweet Shimmer", "hex": "#BF4F51" }, { "name": "Black", "hex": "#000000" }, { "name": "Black Bean", "hex": "#3D0C02" }, { "name": "Black Coral", "hex": "#54626F" }, { "name": "Black Leather Jacket", "hex": "#253529" }, { "name": "Black Olive", "hex": "#3B3C36" }, { "name": "Black Shadows", "hex": "#BFAFB2" }, { "name": "Blanched Almond", "hex": "#FFEBCD" }, { "name": "Blast-Off Bronze", "hex": "#A57164" }, { "name": "Bleu De France", "hex": "#318CE7" }, { "name": "Blizzard Blue", "hex": "#ACE5EE" }, { "name": "Blond", "hex": "#FAF0BE" }, { "name": "Blue", "hex": "#0000FF" }, { "name": "Blue (Crayola)", "hex": "#1F75FE" }, { "name": "Blue (Munsell)", "hex": "#0093AF" }, { "name": "Blue (NCS)", "hex": "#0087BD" }, { "name": "Blue (Pantone)", "hex": "#0018A8" }, { "name": "Blue (Pigment)", "hex": "#333399" }, { "name": "Blue (RYB)", "hex": "#0247FE" }, { "name": "Blue Bell", "hex": "#A2A2D0" }, { "name": "Blue Bolt", "hex": "#00B9FB" }, { "name": "Blue-Gray", "hex": "#6699CC" }, { "name": "Blue-Green", "hex": "#0D98BA" }, { "name": "Blue Jeans", "hex": "#5DADEC" }, { "name": "Blue Lagoon", "hex": "#ACE5EE" }, { "name": "Blue-Magenta Violet", "hex": "#553592" }, { "name": "Blue Sapphire", "hex": "#126180" }, { "name": "Blue-Violet", "hex": "#8A2BE2" }, { "name": "Blue Yonder", "hex": "#5072A7" }, { "name": "Blueberry", "hex": "#4F86F7" }, { "name": "Bluebonnet", "hex": "#1C1CF0" }, { "name": "Blush", "hex": "#DE5D83" }, { "name": "Bole", "hex": "#79443B" }, { "name": "Bondi Blue", "hex": "#0095B6" }, { "name": "Bone", "hex": "#E3DAC9" }, { "name": "Booger Buster", "hex": "#DDE26A" }, { "name": "Boston University Red", "hex": "#CC0000" }, { "name": "Bottle Green", "hex": "#006A4E" }, { "name": "Boysenberry", "hex": "#873260" }, { "name": "Brandeis Blue", "hex": "#0070FF" }, { "name": "Brass", "hex": "#B5A642" }, { "name": "Brick Red", "hex": "#CB4154" }, { "name": "Bright Cerulean", "hex": "#1DACD6" }, { "name": "Bright Green", "hex": "#66FF00" }, { "name": "Bright Lavender", "hex": "#BF94E4" }, { "name": "Bright Lilac", "hex": "#D891EF" }, { "name": "Bright Maroon", "hex": "#C32148" }, { "name": "Bright Navy Blue", "hex": "#1974D2" }, { "name": "Bright Pink", "hex": "#FF007F" }, { "name": "Bright Turquoise", "hex": "#08E8DE" }, { "name": "Bright Ube", "hex": "#D19FE8" }, { "name": "Bright Yellow (Crayola)", "hex": "#FFAA1D" }, { "name": "Brilliant Azure", "hex": "#3399FF" }, { "name": "Brilliant Lavender", "hex": "#F4BBFF" }, { "name": "Brilliant Rose", "hex": "#FF55A3" }, { "name": "Brink Pink", "hex": "#FB607F" }, { "name": "British Racing Green", "hex": "#004225" }, { "name": "Bronze", "hex": "#CD7F32" }, { "name": "Bronze Yellow", "hex": "#737000" }, { "name": "Brown (Traditional)", "hex": "#964B00" }, { "name": "Brown (Web)", "hex": "#A52A2A" }, { "name": "Brown-Nose", "hex": "#6B4423" }, { "name": "Brown Sugar", "hex": "#AF6E4D" }, { "name": "Brown Yellow", "hex": "#cc9966" }, { "name": "Brunswick Green", "hex": "#1B4D3E" }, { "name": "Bubble Gum", "hex": "#FFC1CC" }, { "name": "Bubbles", "hex": "#E7FEFF" }, { "name": "Bud Green", "hex": "#7BB661" }, { "name": "Buff", "hex": "#F0DC82" }, { "name": "Bulgarian Rose", "hex": "#480607" }, { "name": "Burgundy", "hex": "#800020" }, { "name": "Burlywood", "hex": "#DEB887" }, { "name": "Burnished Brown", "hex": "#A17A74" }, { "name": "Burnt Orange", "hex": "#CC5500" }, { "name": "Burnt Sienna", "hex": "#E97451" }, { "name": "Burnt Umber", "hex": "#8A3324" }, { "name": "Button Blue", "hex": "#24A0ED" }, { "name": "Byzantine", "hex": "#BD33A4" }, { "name": "Byzantium", "hex": "#702963" }, { "name": "Cadet", "hex": "#536872" }, { "name": "Cadet Blue", "hex": "#5F9EA0" }, { "name": "Cadet Grey", "hex": "#91A3B0" }, { "name": "Cadmium Green", "hex": "#006B3C" }, { "name": "Cadmium Orange", "hex": "#ED872D" }, { "name": "Cadmium Red", "hex": "#E30022" }, { "name": "Cadmium Yellow", "hex": "#FFF600" }, { "name": "Cafe Au Lait", "hex": "#A67B5B" }, { "name": "Cafe Noir", "hex": "#4B3621" }, { "name": "Cal Poly Pomona Green", "hex": "#1E4D2B" }, { "name": "Cambridge Blue", "hex": "#A3C1AD" }, { "name": "Camel", "hex": "#C19A6B" }, { "name": "Cameo Pink", "hex": "#EFBBCC" }, { "name": "Camouflage Green", "hex": "#78866B" }, { "name": "Canary", "hex": "#FFFF99" }, { "name": "Canary Yellow", "hex": "#FFEF00" }, { "name": "Candy Apple Red", "hex": "#FF0800" }, { "name": "Candy Pink", "hex": "#E4717A" }, { "name": "Capri", "hex": "#00BFFF" }, { "name": "Caput Mortuum", "hex": "#592720" }, { "name": "Cardinal", "hex": "#C41E3A" }, { "name": "Caribbean Green", "hex": "#00CC99" }, { "name": "Carmine", "hex": "#960018" }, { "name": "Carmine (M&P)", "hex": "#D70040" }, { "name": "Carmine Pink", "hex": "#EB4C42" }, { "name": "Carmine Red", "hex": "#FF0038" }, { "name": "Carnation Pink", "hex": "#FFA6C9" }, { "name": "Carnelian", "hex": "#B31B1B" }, { "name": "Carolina Blue", "hex": "#56A0D3" }, { "name": "Carrot Orange", "hex": "#ED9121" }, { "name": "Castleton Green", "hex": "#00563F" }, { "name": "Catalina Blue", "hex": "#062A78" }, { "name": "Catawba", "hex": "#703642" }, { "name": "Cedar Chest", "hex": "#C95A49" }, { "name": "Ceil", "hex": "#92A1CF" }, { "name": "Celadon", "hex": "#ACE1AF" }, { "name": "Celadon Blue", "hex": "#007BA7" }, { "name": "Celadon Green", "hex": "#2F847C" }, { "name": "Celeste", "hex": "#B2FFFF" }, { "name": "Celestial Blue", "hex": "#4997D0" }, { "name": "Cerise", "hex": "#DE3163" }, { "name": "Cerise Pink", "hex": "#EC3B83" }, { "name": "Cerulean", "hex": "#007BA7" }, { "name": "Cerulean Blue", "hex": "#2A52BE" }, { "name": "Cerulean Frost", "hex": "#6D9BC3" }, { "name": "CG Blue", "hex": "#007AA5" }, { "name": "CG Red", "hex": "#E03C31" }, { "name": "Chamoisee", "hex": "#A0785A" }, { "name": "Champagne", "hex": "#F7E7CE" }, { "name": "Champagne Pink", "hex": "#F1DDCF" }, { "name": "Charcoal", "hex": "#36454F" }, { "name": "Charleston Green", "hex": "#232B2B" }, { "name": "Charm Pink", "hex": "#E68FAC" }, { "name": "Chartreuse (Traditional)", "hex": "#DFFF00" }, { "name": "Chartreuse (Web)", "hex": "#7FFF00" }, { "name": "Cherry", "hex": "#DE3163" }, { "name": "Cherry Blossom Pink", "hex": "#FFB7C5" }, { "name": "Chestnut", "hex": "#954535" }, { "name": "China Pink", "hex": "#DE6FA1" }, { "name": "China Rose", "hex": "#A8516E" }, { "name": "Chinese Red", "hex": "#AA381E" }, { "name": "Chinese Violet", "hex": "#856088" }, { "name": "Chlorophyll Green", "hex": "#4AFF00" }, { "name": "Chocolate (Traditional)", "hex": "#7B3F00" }, { "name": "Chocolate (Web)", "hex": "#D2691E" }, { "name": "Chrome Yellow", "hex": "#FFA700" }, { "name": "Cinereous", "hex": "#98817B" }, { "name": "Cinnabar", "hex": "#E34234" }, { "name": "Cinnamon", "hex": "#D2691E" }, { "name": "Cinnamon Satin", "hex": "#CD607E" }, { "name": "Citrine", "hex": "#E4D00A" }, { "name": "Citron", "hex": "#9FA91F" }, { "name": "Claret", "hex": "#7F1734" }, { "name": "Classic Rose", "hex": "#FBCCE7" }, { "name": "Cobalt Blue", "hex": "#0047AB" }, { "name": "Cocoa Brown", "hex": "#D2691E" }, { "name": "Coconut", "hex": "#965A3E" }, { "name": "Coffee", "hex": "#6F4E37" }, { "name": "Columbia Blue", "hex": "#C4D8E2" }, { "name": "Congo Pink", "hex": "#F88379" }, { "name": "Cool Black", "hex": "#002E63" }, { "name": "Cool Grey", "hex": "#8C92AC" }, { "name": "Copper", "hex": "#B87333" }, { "name": "Copper (Crayola)", "hex": "#DA8A67" }, { "name": "Copper Penny", "hex": "#AD6F69" }, { "name": "Copper Red", "hex": "#CB6D51" }, { "name": "Copper Rose", "hex": "#996666" }, { "name": "Coquelicot", "hex": "#FF3800" }, { "name": "Coral", "hex": "#FF7F50" }, { "name": "Coral Pink", "hex": "#F88379" }, { "name": "Coral Red", "hex": "#FF4040" }, { "name": "Coral Reef", "hex": "#FD7C6E" }, { "name": "Cordovan", "hex": "#893F45" }, { "name": "Corn", "hex": "#FBEC5D" }, { "name": "Cornell Red", "hex": "#B31B1B" }, { "name": "Cornflower Blue", "hex": "#6495ED" }, { "name": "Cornsilk", "hex": "#FFF8DC" }, { "name": "Cosmic Cobalt", "hex": "#2E2D88" }, { "name": "Cosmic Latte", "hex": "#FFF8E7" }, { "name": "Coyote Brown", "hex": "#81613C" }, { "name": "Cotton Candy", "hex": "#FFBCD9" }, { "name": "Cream", "hex": "#FFFDD0" }, { "name": "Crimson", "hex": "#DC143C" }, { "name": "Crimson Glory", "hex": "#BE0032" }, { "name": "Crimson Red", "hex": "#990000" }, { "name": "Cultured", "hex": "#F5F5F5" }, { "name": "Cyan", "hex": "#00FFFF" }, { "name": "Cyan Azure", "hex": "#4E82B4" }, { "name": "Cyan-Blue Azure", "hex": "#4682BF" }, { "name": "Cyan Cobalt Blue", "hex": "#28589C" }, { "name": "Cyan Cornflower Blue", "hex": "#188BC2" }, { "name": "Cyan (Process)", "hex": "#00B7EB" }, { "name": "Cyber Grape", "hex": "#58427C" }, { "name": "Cyber Yellow", "hex": "#FFD300" }, { "name": "Cyclamen", "hex": "#F56FA1" }, { "name": "Daffodil", "hex": "#FFFF31" }, { "name": "Dandelion", "hex": "#F0E130" }, { "name": "Dark Blue", "hex": "#00008B" }, { "name": "Dark Blue-Gray", "hex": "#666699" }, { "name": "Dark Brown", "hex": "#654321" }, { "name": "Dark Brown-Tangelo", "hex": "#88654E" }, { "name": "Dark Byzantium", "hex": "#5D3954" }, { "name": "Dark Candy Apple Red", "hex": "#A40000" }, { "name": "Dark Cerulean", "hex": "#08457E" }, { "name": "Dark Chestnut", "hex": "#986960" }, { "name": "Dark Coral", "hex": "#CD5B45" }, { "name": "Dark Cyan", "hex": "#008B8B" }, { "name": "Dark Electric Blue", "hex": "#536878" }, { "name": "Dark Goldenrod", "hex": "#B8860B" }, { "name": "Dark Gray (X11)", "hex": "#A9A9A9" }, { "name": "Dark Green", "hex": "#013220" }, { "name": "Dark Green (X11)", "hex": "#006400" }, { "name": "Dark Gunmetal", "hex": "#1F262A" }, { "name": "Dark Imperial Blue", "hex": "#00416A" }, { "name": "Dark Imperial Blue", "hex": "#00147E" }, { "name": "Dark Jungle Green", "hex": "#1A2421" }, { "name": "Dark Khaki", "hex": "#BDB76B" }, { "name": "Dark Lava", "hex": "#483C32" }, { "name": "Dark Lavender", "hex": "#734F96" }, { "name": "Dark Liver", "hex": "#534B4F" }, { "name": "Dark Liver (Horses)", "hex": "#543D37" }, { "name": "Dark Magenta", "hex": "#8B008B" }, { "name": "Dark Medium Gray", "hex": "#A9A9A9" }, { "name": "Dark Midnight Blue", "hex": "#003366" }, { "name": "Dark Moss Green", "hex": "#4A5D23" }, { "name": "Dark Olive Green", "hex": "#556B2F" }, { "name": "Dark Orange", "hex": "#FF8C00" }, { "name": "Dark Orchid", "hex": "#9932CC" }, { "name": "Dark Pastel Blue", "hex": "#779ECB" }, { "name": "Dark Pastel Green", "hex": "#03C03C" }, { "name": "Dark Pastel Purple", "hex": "#966FD6" }, { "name": "Dark Pastel Red", "hex": "#C23B22" }, { "name": "Dark Pink", "hex": "#E75480" }, { "name": "Dark Powder Blue", "hex": "#003399" }, { "name": "Dark Puce", "hex": "#4F3A3C" }, { "name": "Dark Purple", "hex": "#301934" }, { "name": "Dark Raspberry", "hex": "#872657" }, { "name": "Dark Red", "hex": "#8B0000" }, { "name": "Dark Salmon", "hex": "#E9967A" }, { "name": "Dark Scarlet", "hex": "#560319" }, { "name": "Dark Sea Green", "hex": "#8FBC8F" }, { "name": "Dark Sienna", "hex": "#3C1414" }, { "name": "Dark Sky Blue", "hex": "#8CBED6" }, { "name": "Dark Slate Blue", "hex": "#483D8B" }, { "name": "Dark Slate Gray", "hex": "#2F4F4F" }, { "name": "Dark Spring Green", "hex": "#177245" }, { "name": "Dark Tan", "hex": "#918151" }, { "name": "Dark Tangerine", "hex": "#FFA812" }, { "name": "Dark Taupe", "hex": "#483C32" }, { "name": "Dark Terra Cotta", "hex": "#CC4E5C" }, { "name": "Dark Turquoise", "hex": "#00CED1" }, { "name": "Dark Vanilla", "hex": "#D1BEA8" }, { "name": "Dark Violet", "hex": "#9400D3" }, { "name": "Dark Yellow", "hex": "#9B870C" }, { "name": "Dartmouth Green", "hex": "#00703C" }, { "name": "Davy's Grey", "hex": "#555555" }, { "name": "Debian Red", "hex": "#D70A53" }, { "name": "Deep Aquamarine", "hex": "#40826D" }, { "name": "Deep Carmine", "hex": "#A9203E" }, { "name": "Deep Carmine Pink", "hex": "#EF3038" }, { "name": "Deep Carrot Orange", "hex": "#E9692C" }, { "name": "Deep Cerise", "hex": "#DA3287" }, { "name": "Deep Champagne", "hex": "#FAD6A5" }, { "name": "Deep Chestnut", "hex": "#B94E48" }, { "name": "Deep Coffee", "hex": "#704241" }, { "name": "Deep Fuchsia", "hex": "#C154C1" }, { "name": "Deep Green", "hex": "#056608" }, { "name": "Deep Green-Cyan Turquoise", "hex": "#0E7C61" }, { "name": "Deep Jungle Green", "hex": "#004B49" }, { "name": "Deep Koamaru", "hex": "#333366" }, { "name": "Deep Lemon", "hex": "#F5C71A" }, { "name": "Deep Lilac", "hex": "#9955BB" }, { "name": "Deep Magenta", "hex": "#CC00CC" }, { "name": "Deep Maroon", "hex": "#820000" }, { "name": "Deep Mauve", "hex": "#D473D4" }, { "name": "Deep Moss Green", "hex": "#355E3B" }, { "name": "Deep Peach", "hex": "#FFCBA4" }, { "name": "Deep Pink", "hex": "#FF1493" }, { "name": "Deep Puce", "hex": "#A95C68" }, { "name": "Deep Red", "hex": "#850101" }, { "name": "Deep Ruby", "hex": "#843F5B" }, { "name": "Deep Saffron", "hex": "#FF9933" }, { "name": "Deep Sky Blue", "hex": "#00BFFF" }, { "name": "Deep Space Sparkle", "hex": "#4A646C" }, { "name": "Deep Spring Bud", "hex": "#556B2F" }, { "name": "Deep Taupe", "hex": "#7E5E60" }, { "name": "Deep Tuscan Red", "hex": "#66424D" }, { "name": "Deep Violet", "hex": "#330066" }, { "name": "Deer", "hex": "#BA8759" }, { "name": "Denim", "hex": "#1560BD" }, { "name": "Denim Blue", "hex": "#2243B6" }, { "name": "Desaturated Cyan", "hex": "#669999" }, { "name": "Desert", "hex": "#C19A6B" }, { "name": "Desert Sand", "hex": "#EDC9AF" }, { "name": "Desire", "hex": "#EA3C53" }, { "name": "Diamond", "hex": "#B9F2FF" }, { "name": "Dim Gray", "hex": "#696969" }, { "name": "Dingy Dungeon", "hex": "#C53151" }, { "name": "Dirt", "hex": "#9B7653" }, { "name": "Dodger Blue", "hex": "#1E90FF" }, { "name": "Dodie Yellow", "hex": "#FEF65B" }, { "name": "Dogwood Rose", "hex": "#D71868" }, { "name": "Dollar Bill", "hex": "#85BB65" }, { "name": "Dolphin Gray", "hex": "#828E84" }, { "name": "Donkey Brown", "hex": "#664C28" }, { "name": "Drab", "hex": "#967117" }, { "name": "Duke Blue", "hex": "#00009C" }, { "name": "Dust Storm", "hex": "#E5CCC9" }, { "name": "Dutch White", "hex": "#EFDFBB" }, { "name": "Earth Yellow", "hex": "#E1A95F" }, { "name": "Ebony", "hex": "#555D50" }, { "name": "Ecru", "hex": "#C2B280" }, { "name": "Eerie Black", "hex": "#1B1B1B" }, { "name": "Eggplant", "hex": "#614051" }, { "name": "Eggshell", "hex": "#F0EAD6" }, { "name": "Egyptian Blue", "hex": "#1034A6" }, { "name": "Electric Blue", "hex": "#7DF9FF" }, { "name": "Electric Crimson", "hex": "#FF003F" }, { "name": "Electric Cyan", "hex": "#00FFFF" }, { "name": "Electric Green", "hex": "#00FF00" }, { "name": "Electric Indigo", "hex": "#6F00FF" }, { "name": "Electric Lavender", "hex": "#F4BBFF" }, { "name": "Electric Lime", "hex": "#CCFF00" }, { "name": "Electric Purple", "hex": "#BF00FF" }, { "name": "Electric Ultramarine", "hex": "#3F00FF" }, { "name": "Electric Violet", "hex": "#8F00FF" }, { "name": "Electric Yellow", "hex": "#FFFF33" }, { "name": "Emerald", "hex": "#50C878" }, { "name": "Eminence", "hex": "#6C3082" }, { "name": "English Green", "hex": "#1B4D3E" }, { "name": "English Lavender", "hex": "#B48395" }, { "name": "English Red", "hex": "#AB4B52" }, { "name": "English Vermillion", "hex": "#CC474B" }, { "name": "English Violet", "hex": "#563C5C" }, { "name": "Eton Blue", "hex": "#96C8A2" }, { "name": "Eucalyptus", "hex": "#44D7A8" }, { "name": "Fallow", "hex": "#C19A6B" }, { "name": "Falu Red", "hex": "#801818" }, { "name": "Fandango", "hex": "#B53389" }, { "name": "Fandango Pink", "hex": "#DE5285" }, { "name": "Fashion Fuchsia", "hex": "#F400A1" }, { "name": "Fawn", "hex": "#E5AA70" }, { "name": "Feldgrau", "hex": "#4D5D53" }, { "name": "Feldspar", "hex": "#FDD5B1" }, { "name": "Fern Green", "hex": "#4F7942" }, { "name": "Ferrari Red", "hex": "#FF2800" }, { "name": "Field Drab", "hex": "#6C541E" }, { "name": "Fiery Rose", "hex": "#FF5470" }, { "name": "Firebrick", "hex": "#B22222" }, { "name": "Fire Engine Red", "hex": "#CE2029" }, { "name": "Flame", "hex": "#E25822" }, { "name": "Flamingo Pink", "hex": "#FC8EAC" }, { "name": "Flattery", "hex": "#6B4423" }, { "name": "Flavescent", "hex": "#F7E98E" }, { "name": "Flax", "hex": "#EEDC82" }, { "name": "Flirt", "hex": "#A2006D" }, { "name": "Floral White", "hex": "#FFFAF0" }, { "name": "Fluorescent Orange", "hex": "#FFBF00" }, { "name": "Fluorescent Pink", "hex": "#FF1493" }, { "name": "Fluorescent Yellow", "hex": "#CCFF00" }, { "name": "Folly", "hex": "#FF004F" }, { "name": "Forest Green (Traditional)", "hex": "#014421" }, { "name": "Forest Green (Web)", "hex": "#228B22" }, { "name": "French Beige", "hex": "#A67B5B" }, { "name": "French Bistre", "hex": "#856D4D" }, { "name": "French Blue", "hex": "#0072BB" }, { "name": "French Fuchsia", "hex": "#FD3F92" }, { "name": "French Lilac", "hex": "#86608E" }, { "name": "French Lime", "hex": "#9EFD38" }, { "name": "French Mauve", "hex": "#D473D4" }, { "name": "French Pink", "hex": "#FD6C9E" }, { "name": "French Plum", "hex": "#811453" }, { "name": "French Puce", "hex": "#4E1609" }, { "name": "French Raspberry", "hex": "#C72C48" }, { "name": "French Rose", "hex": "#F64A8A" }, { "name": "French Sky Blue", "hex": "#77B5FE" }, { "name": "French Violet", "hex": "#8806CE" }, { "name": "French Wine", "hex": "#AC1E44" }, { "name": "Fresh Air", "hex": "#A6E7FF" }, { "name": "Frogert", "hex": "#E936A7" }, { "name": "Fuchsia", "hex": "#FF00FF" }, { "name": "Fuchsia (Crayola)", "hex": "#C154C1" }, { "name": "Fuchsia Pink", "hex": "#FF77FF" }, { "name": "Fuchsia Purple", "hex": "#CC397B" }, { "name": "Fuchsia Rose", "hex": "#C74375" }, { "name": "Fulvous", "hex": "#E48400" }, { "name": "Fuzzy Wuzzy", "hex": "#CC6666" }, { "name": "Gainsboro", "hex": "#DCDCDC" }, { "name": "Gamboge", "hex": "#E49B0F" }, { "name": "Gamboge Orange (Brown)", "hex": "#996600" }, { "name": "Gargoyle Gas", "hex": "#FFDF46" }, { "name": "Generic Viridian", "hex": "#007F66" }, { "name": "Ghost White", "hex": "#F8F8FF" }, { "name": "Giant's Club", "hex": "#B05C52" }, { "name": "Giants Orange", "hex": "#FE5A1D" }, { "name": "Ginger", "hex": "#B06500" }, { "name": "Glaucous", "hex": "#6082B6" }, { "name": "Glitter", "hex": "#E6E8FA" }, { "name": "Glossy Grape", "hex": "#AB92B3" }, { "name": "GO Green", "hex": "#00AB66" }, { "name": "Gold (Metallic)", "hex": "#D4AF37" }, { "name": "Gold (Web) (Golden)", "hex": "#FFD700" }, { "name": "Gold Fusion", "hex": "#85754E" }, { "name": "Golden Brown", "hex": "#996515" }, { "name": "Golden Poppy", "hex": "#FCC200" }, { "name": "Golden Yellow", "hex": "#FFDF00" }, { "name": "Goldenrod", "hex": "#DAA520" }, { "name": "Granite Gray", "hex": "#676767" }, { "name": "Granny Smith Apple", "hex": "#A8E4A0" }, { "name": "Grape", "hex": "#6F2DA8" }, { "name": "Gray", "hex": "#808080" }, { "name": "Gray (HTML/CSS Gray)", "hex": "#808080" }, { "name": "Gray (X11 Gray)", "hex": "#BEBEBE" }, { "name": "Gray-Asparagus", "hex": "#465945" }, { "name": "Gray-Blue", "hex": "#8C92AC" }, { "name": "Green (Color Wheel) (X11 Green)", "hex": "#00FF00" }, { "name": "Green (Crayola)", "hex": "#1CAC78" }, { "name": "Green (HTML/CSS Color)", "hex": "#008000" }, { "name": "Green (Munsell)", "hex": "#00A877" }, { "name": "Green (NCS)", "hex": "#009F6B" }, { "name": "Green (Pantone)", "hex": "#00AD43" }, { "name": "Green (Pigment)", "hex": "#00A550" }, { "name": "Green (RYB)", "hex": "#66B032" }, { "name": "Green-Blue", "hex": "#1164B4" }, { "name": "Green-Cyan", "hex": "#009966" }, { "name": "Green Lizard", "hex": "#A7F432" }, { "name": "Green Sheen", "hex": "#6EAEA1" }, { "name": "Green-Yellow", "hex": "#ADFF2F" }, { "name": "Grizzly", "hex": "#885818" }, { "name": "Grullo", "hex": "#A99A86" }, { "name": "Guppie Green", "hex": "#00FF7F" }, { "name": "Gunmetal", "hex": "#2a3439" }, { "name": "Halaya Ube", "hex": "#663854" }, { "name": "Han Blue", "hex": "#446CCF" }, { "name": "Han Purple", "hex": "#5218FA" }, { "name": "Hansa Yellow", "hex": "#E9D66B" }, { "name": "Harlequin", "hex": "#3FFF00" }, { "name": "Harlequin Green", "hex": "#46CB18" }, { "name": "Harvard Crimson", "hex": "#C90016" }, { "name": "Harvest Gold", "hex": "#DA9100" }, { "name": "Heart Gold", "hex": "#808000" }, { "name": "Heat Wave", "hex": "#FF7A00" }, { "name": "Heidelberg Red", "hex": "#960018" }, { "name": "Heliotrope", "hex": "#DF73FF" }, { "name": "Heliotrope Gray", "hex": "#AA98A9" }, { "name": "Heliotrope Magenta", "hex": "#AA00BB" }, { "name": "Hollywood Cerise", "hex": "#F400A1" }, { "name": "Honeydew", "hex": "#F0FFF0" }, { "name": "Honolulu Blue", "hex": "#006DB0" }, { "name": "Hooker's Green", "hex": "#49796B" }, { "name": "Hot Magenta", "hex": "#FF1DCE" }, { "name": "Hot Pink", "hex": "#FF69B4" }, { "name": "Hunter Green", "hex": "#355E3B" }, { "name": "Iceberg", "hex": "#71A6D2" }, { "name": "Icterine", "hex": "#FCF75E" }, { "name": "Iguana Green", "hex": "#71BC78" }, { "name": "Illuminating Emerald", "hex": "#319177" }, { "name": "Imperial", "hex": "#602F6B" }, { "name": "Imperial Blue", "hex": "#002395" }, { "name": "Imperial Purple", "hex": "#66023C" }, { "name": "Imperial Red", "hex": "#ED2939" }, { "name": "Inchworm", "hex": "#B2EC5D" }, { "name": "Independence", "hex": "#4C516D" }, { "name": "India Green", "hex": "#138808" }, { "name": "Indian Red", "hex": "#CD5C5C" }, { "name": "Indian Yellow", "hex": "#E3A857" }, { "name": "Indigo", "hex": "#4B0082" }, { "name": "Indigo Dye", "hex": "#091F92" }, { "name": "Indigo (Web)", "hex": "#4B0082" }, { "name": "Infra Red", "hex": "#FF496C" }, { "name": "Interdimensional Blue", "hex": "#360CCC" }, { "name": "International Klein Blue", "hex": "#002FA7" }, { "name": "International Orange (Aerospace)", "hex": "#FF4F00" }, { "name": "International Orange (Engineering)", "hex": "#BA160C" }, { "name": "International Orange (Golden Gate Bridge)", "hex": "#C0362C" }, { "name": "Iris", "hex": "#5A4FCF" }, { "name": "Irresistible", "hex": "#B3446C" }, { "name": "Isabelline", "hex": "#F4F0EC" }, { "name": "Islamic Green", "hex": "#009000" }, { "name": "Italian Sky Blue", "hex": "#B2FFFF" }, { "name": "Ivory", "hex": "#FFFFF0" }, { "name": "Jade", "hex": "#00A86B" }, { "name": "Japanese Carmine", "hex": "#9D2933" }, { "name": "Japanese Indigo", "hex": "#264348" }, { "name": "Japanese Violet", "hex": "#5B3256" }, { "name": "Jasmine", "hex": "#F8DE7E" }, { "name": "Jasper", "hex": "#D73B3E" }, { "name": "Jazzberry Jam", "hex": "#A50B5E" }, { "name": "Jelly Bean", "hex": "#DA614E" }, { "name": "Jet", "hex": "#343434" }, { "name": "Jonquil", "hex": "#F4CA16" }, { "name": "Jordy Blue", "hex": "#8AB9F1" }, { "name": "June Bud", "hex": "#BDDA57" }, { "name": "Jungle Green", "hex": "#29AB87" }, { "name": "Kelly Green", "hex": "#4CBB17" }, { "name": "Kenyan Copper", "hex": "#7C1C05" }, { "name": "Keppel", "hex": "#3AB09E" }, { "name": "Key Lime", "hex": "#E8F48C" }, { "name": "Khaki (HTML/CSS) (Khaki)", "hex": "#C3B091" }, { "name": "Khaki (X11) (Light Khaki)", "hex": "#F0E68C" }, { "name": "Kiwi", "hex": "#8EE53F" }, { "name": "Kobe", "hex": "#882D17" }, { "name": "Kobi", "hex": "#E79FC4" }, { "name": "Kobicha", "hex": "#6B4423" }, { "name": "Kombu Green", "hex": "#354230" }, { "name": "KSU Purple", "hex": "#512888" }, { "name": "KU Crimson", "hex": "#E8000D" }, { "name": "La Salle Green", "hex": "#087830" }, { "name": "Languid Lavender", "hex": "#D6CADD" }, { "name": "Lapis Lazuli", "hex": "#26619C" }, { "name": "Laser Lemon", "hex": "#FFFF66" }, { "name": "Laurel Green", "hex": "#A9BA9D" }, { "name": "Lava", "hex": "#CF1020" }, { "name": "Lavender (Floral)", "hex": "#B57EDC" }, { "name": "Lavender (Web)", "hex": "#E6E6FA" }, { "name": "Lavender Blue", "hex": "#CCCCFF" }, { "name": "Lavender Blush", "hex": "#FFF0F5" }, { "name": "Lavender Gray", "hex": "#C4C3D0" }, { "name": "Lavender Indigo", "hex": "#9457EB" }, { "name": "Lavender Magenta", "hex": "#EE82EE" }, { "name": "Lavender Mist", "hex": "#E6E6FA" }, { "name": "Lavender Pink", "hex": "#FBAED2" }, { "name": "Lavender Purple", "hex": "#967BB6" }, { "name": "Lavender Rose", "hex": "#FBA0E3" }, { "name": "Lawn Green", "hex": "#7CFC00" }, { "name": "Lemon", "hex": "#FFF700" }, { "name": "Lemon Chiffon", "hex": "#FFFACD" }, { "name": "Lemon Curry", "hex": "#CCA01D" }, { "name": "Lemon Glacier", "hex": "#FDFF00" }, { "name": "Lemon Lime", "hex": "#E3FF00" }, { "name": "Lemon Meringue", "hex": "#F6EABE" }, { "name": "Lemon Yellow", "hex": "#FFF44F" }, { "name": "Licorice", "hex": "#1A1110" }, { "name": "Liberty", "hex": "#545AA7" }, { "name": "Light Apricot", "hex": "#FDD5B1" }, { "name": "Light Blue", "hex": "#ADD8E6" }, { "name": "Light Brown", "hex": "#B5651D" }, { "name": "Light Carmine Pink", "hex": "#E66771" }, { "name": "Light Cobalt Blue", "hex": "#88ACE0" }, { "name": "Light Coral", "hex": "#F08080" }, { "name": "Light Cornflower Blue", "hex": "#93CCEA" }, { "name": "Light Crimson", "hex": "#F56991" }, { "name": "Light Cyan", "hex": "#E0FFFF" }, { "name": "Light Deep Pink", "hex": "#FF5CCD" }, { "name": "Light French Beige", "hex": "#C8AD7F" }, { "name": "Light Fuchsia Pink", "hex": "#F984EF" }, { "name": "Light Goldenrod Yellow", "hex": "#FAFAD2" }, { "name": "Light Gray", "hex": "#D3D3D3" }, { "name": "Light Grayish Magenta", "hex": "#CC99CC" }, { "name": "Light Green", "hex": "#90EE90" }, { "name": "Light Hot Pink", "hex": "#FFB3DE" }, { "name": "Light Khaki", "hex": "#F0E68C" }, { "name": "Light Medium Orchid", "hex": "#D39BCB" }, { "name": "Light Moss Green", "hex": "#ADDFAD" }, { "name": "Light Orange", "hex": "#FED8B1" }, { "name": "Light Orchid", "hex": "#E6A8D7" }, { "name": "Light Pastel Purple", "hex": "#B19CD9" }, { "name": "Light Pink", "hex": "#FFB6C1" }, { "name": "Light Red Ochre", "hex": "#E97451" }, { "name": "Light Salmon", "hex": "#FFA07A" }, { "name": "Light Salmon Pink", "hex": "#FF9999" }, { "name": "Light Sea Green", "hex": "#20B2AA" }, { "name": "Light Sky Blue", "hex": "#87CEFA" }, { "name": "Light Slate Gray", "hex": "#778899" }, { "name": "Light Steel Blue", "hex": "#B0C4DE" }, { "name": "Light Taupe", "hex": "#B38B6D" }, { "name": "Light Thulian Pink", "hex": "#E68FAC" }, { "name": "Light Yellow", "hex": "#FFFFE0" }, { "name": "Lilac", "hex": "#C8A2C8" }, { "name": "Lilac Luster", "hex": "#AE98AA" }, { "name": "Lime (Color Wheel)", "hex": "#BFFF00" }, { "name": "Lime (Web) (X11 Green)", "hex": "#00FF00" }, { "name": "Lime Green", "hex": "#32CD32" }, { "name": "Limerick", "hex": "#9DC209" }, { "name": "Lincoln Green", "hex": "#195905" }, { "name": "Linen", "hex": "#FAF0E6" }, { "name": "Loeen (Lopen) Look", "hex": "#15F2FD" }, { "name": "Liseran Purple", "hex": "#DE6FA1" }, { "name": "Little Boy Blue", "hex": "#6CA0DC" }, { "name": "Liver", "hex": "#674C47" }, { "name": "Liver (Dogs)", "hex": "#B86D29" }, { "name": "Liver (Organ)", "hex": "#6C2E1F" }, { "name": "Liver Chestnut", "hex": "#987456" }, { "name": "Livid", "hex": "#6699CC" }, { "name": "Lumber", "hex": "#FFE4CD" }, { "name": "Lust", "hex": "#E62020" }, { "name": "Maastricht Blue", "hex": "#001C3D" }, { "name": "Macaroni And Cheese", "hex": "#FFBD88" }, { "name": "Madder Lake", "hex": "#CC3336" }, { "name": "Magenta", "hex": "#FF00FF" }, { "name": "Magenta (Crayola)", "hex": "#FF55A3" }, { "name": "Magenta (Dye)", "hex": "#CA1F7B" }, { "name": "Magenta (Pantone)", "hex": "#D0417E" }, { "name": "Magenta (Process)", "hex": "#FF0090" }, { "name": "Magenta Haze", "hex": "#9F4576" }, { "name": "Magenta-Pink", "hex": "#CC338B" }, { "name": "Magic Mint", "hex": "#AAF0D1" }, { "name": "Magic Potion", "hex": "#FF4466" }, { "name": "Magnolia", "hex": "#F8F4FF" }, { "name": "Mahogany", "hex": "#C04000" }, { "name": "Maize", "hex": "#FBEC5D" }, { "name": "Majorelle Blue", "hex": "#6050DC" }, { "name": "Malachite", "hex": "#0BDA51" }, { "name": "Manatee", "hex": "#979AAA" }, { "name": "Mandarin", "hex": "#F37A48" }, { "name": "Mango Tango", "hex": "#FF8243" }, { "name": "Mantis", "hex": "#74C365" }, { "name": "Mardi Gras", "hex": "#880085" }, { "name": "Marigold", "hex": "#EAA221" }, { "name": "Maroon (Crayola)", "hex": "#C32148" }, { "name": "Maroon (HTML/CSS)", "hex": "#800000" }, { "name": "Maroon (X11)", "hex": "#B03060" }, { "name": "Mauve", "hex": "#E0B0FF" }, { "name": "Mauve Taupe", "hex": "#915F6D" }, { "name": "Mauvelous", "hex": "#EF98AA" }, { "name": "Maximum Blue", "hex": "#47ABCC" }, { "name": "Maximum Blue Green", "hex": "#30BFBF" }, { "name": "Maximum Blue Purple", "hex": "#ACACE6" }, { "name": "Maximum Green", "hex": "#5E8C31" }, { "name": "Maximum Green Yellow", "hex": "#D9E650" }, { "name": "Maximum Purple", "hex": "#733380" }, { "name": "Maximum Red", "hex": "#D92121" }, { "name": "Maximum Red Purple", "hex": "#A63A79" }, { "name": "Maximum Yellow", "hex": "#FAFA37" }, { "name": "Maximum Yellow Red", "hex": "#F2BA49" }, { "name": "May Green", "hex": "#4C9141" }, { "name": "Maya Blue", "hex": "#73C2FB" }, { "name": "Meat Brown", "hex": "#E5B73B" }, { "name": "Medium Aquamarine", "hex": "#66DDAA" }, { "name": "Medium Blue", "hex": "#0000CD" }, { "name": "Medium Candy Apple Red", "hex": "#E2062C" }, { "name": "Medium Carmine", "hex": "#AF4035" }, { "name": "Medium Champagne", "hex": "#F3E5AB" }, { "name": "Medium Electric Blue", "hex": "#035096" }, { "name": "Medium Jungle Green", "hex": "#1C352D" }, { "name": "Medium Lavender Magenta", "hex": "#DDA0DD" }, { "name": "Medium Orchid", "hex": "#BA55D3" }, { "name": "Medium Persian Blue", "hex": "#0067A5" }, { "name": "Medium Purple", "hex": "#9370DB" }, { "name": "Medium Red-Violet", "hex": "#BB3385" }, { "name": "Medium Ruby", "hex": "#AA4069" }, { "name": "Medium Sea Green", "hex": "#3CB371" }, { "name": "Medium Sky Blue", "hex": "#80DAEB" }, { "name": "Medium Slate Blue", "hex": "#7B68EE" }, { "name": "Medium Spring Bud", "hex": "#C9DC87" }, { "name": "Medium Spring Green", "hex": "#00FA9A" }, { "name": "Medium Taupe", "hex": "#674C47" }, { "name": "Medium Turquoise", "hex": "#48D1CC" }, { "name": "Medium Tuscan Red", "hex": "#79443B" }, { "name": "Medium Vermilion", "hex": "#D9603B" }, { "name": "Medium Violet-Red", "hex": "#C71585" }, { "name": "Mellow Apricot", "hex": "#F8B878" }, { "name": "Mellow Yellow", "hex": "#F8DE7E" }, { "name": "Melon", "hex": "#FDBCB4" }, { "name": "Metallic Seaweed", "hex": "#0A7E8C" }, { "name": "Metallic Sunburst", "hex": "#9C7C38" }, { "name": "Mexican Pink", "hex": "#E4007C" }, { "name": "Middle Blue", "hex": "#7ED4E6" }, { "name": "Middle Blue Green", "hex": "#8DD9CC" }, { "name": "Middle Blue Purple", "hex": "#8B72BE" }, { "name": "Middle Red Purple", "hex": "#210837" }, { "name": "Middle Green", "hex": "#4D8C57" }, { "name": "Middle Green Yellow", "hex": "#ACBF60" }, { "name": "Middle Purple", "hex": "#D982B5" }, { "name": "Middle Red", "hex": "#E58E73" }, { "name": "Middle Red Purple", "hex": "#A55353" }, { "name": "Middle Yellow", "hex": "#FFEB00" }, { "name": "Middle Yellow Red", "hex": "#ECB176" }, { "name": "Midnight", "hex": "#702670" }, { "name": "Midnight Blue", "hex": "#191970" }, { "name": "Midnight Green (Eagle Green)", "hex": "#004953" }, { "name": "Mikado Yellow", "hex": "#FFC40C" }, { "name": "Milk", "hex": "#FDFFF5" }, { "name": "Mimi Pink", "hex": "#FFDAE9" }, { "name": "Mindaro", "hex": "#E3F988" }, { "name": "Ming", "hex": "#36747D" }, { "name": "Minion Yellow", "hex": "#F5E050" }, { "name": "Mint", "hex": "#3EB489" }, { "name": "Mint Cream", "hex": "#F5FFFA" }, { "name": "Mint Green", "hex": "#98FF98" }, { "name": "Misty Moss", "hex": "#BBB477" }, { "name": "Misty Rose", "hex": "#FFE4E1" }, { "name": "Moccasin", "hex": "#FAEBD7" }, { "name": "Mode Beige", "hex": "#967117" }, { "name": "Moonstone Blue", "hex": "#73A9C2" }, { "name": "Mordant Red 19", "hex": "#AE0C00" }, { "name": "Morning Blue", "hex": "#8DA399" }, { "name": "Moss Green", "hex": "#8A9A5B" }, { "name": "Mountain Meadow", "hex": "#30BA8F" }, { "name": "Mountbatten Pink", "hex": "#997A8D" }, { "name": "MSU Green", "hex": "#18453B" }, { "name": "Mughal Green", "hex": "#306030" }, { "name": "Mulberry", "hex": "#C54B8C" }, { "name": "Mummy's Tomb", "hex": "#828E84" }, { "name": "Mustard", "hex": "#FFDB58" }, { "name": "Myrtle Green", "hex": "#317873" }, { "name": "Mystic", "hex": "#D65282" }, { "name": "Mystic Maroon", "hex": "#AD4379" }, { "name": "Nadeshiko Pink", "hex": "#F6ADC6" }, { "name": "Napier Green", "hex": "#2A8000" }, { "name": "Naples Yellow", "hex": "#FADA5E" }, { "name": "Navajo White", "hex": "#FFDEAD" }, { "name": "Navy", "hex": "#000080" }, { "name": "Navy Purple", "hex": "#9457EB" }, { "name": "Neon Carrot", "hex": "#FFA343" }, { "name": "Neon Fuchsia", "hex": "#FE4164" }, { "name": "Neon Green", "hex": "#39FF14" }, { "name": "New Car", "hex": "#214FC6" }, { "name": "New York Pink", "hex": "#D7837F" }, { "name": "Nickel", "hex": "#727472" }, { "name": "Non-Photo Blue", "hex": "#A4DDED" }, { "name": "North Texas Green", "hex": "#059033" }, { "name": "Nyanza", "hex": "#E9FFDB" }, { "name": "Ocean Blue", "hex": "#4F42B5" }, { "name": "Ocean Boat Blue", "hex": "#0077BE" }, { "name": "Ocean Green", "hex": "#48BF91" }, { "name": "Ochre", "hex": "#CC7722" }, { "name": "Office Green", "hex": "#008000" }, { "name": "Ogre Odor", "hex": "#FD5240" }, { "name": "Old Burgundy", "hex": "#43302E" }, { "name": "Old Gold", "hex": "#CFB53B" }, { "name": "Old Heliotrope", "hex": "#563C5C" }, { "name": "Old Lace", "hex": "#FDF5E6" }, { "name": "Old Lavender", "hex": "#796878" }, { "name": "Old Mauve", "hex": "#673147" }, { "name": "Old Moss Green", "hex": "#867E36" }, { "name": "Old Rose", "hex": "#C08081" }, { "name": "Old Silver", "hex": "#848482" }, { "name": "Olive", "hex": "#808000" }, { "name": "Olive Drab (#3)", "hex": "#6B8E23" }, { "name": "Olive Drab #7", "hex": "#3C341F" }, { "name": "Olivine", "hex": "#9AB973" }, { "name": "Onyx", "hex": "#353839" }, { "name": "Opera Mauve", "hex": "#B784A7" }, { "name": "Orange (Color Wheel)", "hex": "#FF7F00" }, { "name": "Orange (Crayola)", "hex": "#FF7538" }, { "name": "Orange (Pantone)", "hex": "#FF5800" }, { "name": "Orange (RYB)", "hex": "#FB9902" }, { "name": "Orange (Web)", "hex": "#FFA500" }, { "name": "Orange Peel", "hex": "#FF9F00" }, { "name": "Orange-Red", "hex": "#FF4500" }, { "name": "Orange Soda", "hex": "#FA5B3D" }, { "name": "Orange-Yellow", "hex": "#F8D568" }, { "name": "Orchid", "hex": "#DA70D6" }, { "name": "Orchid Pink", "hex": "#F2BDCD" }, { "name": "Orioles Orange", "hex": "#FB4F14" }, { "name": "Otter Brown", "hex": "#654321" }, { "name": "Outer Space", "hex": "#414A4C" }, { "name": "Outrageous Orange", "hex": "#FF6E4A" }, { "name": "Oxford Blue", "hex": "#002147" }, { "name": "OU Crimson Red", "hex": "#990000" }, { "name": "Pacific Blue", "hex": "#1CA9C9" }, { "name": "Pakistan Green", "hex": "#006600" }, { "name": "Palatinate Blue", "hex": "#273BE2" }, { "name": "Palatinate Purple", "hex": "#682860" }, { "name": "Pale Aqua", "hex": "#BCD4E6" }, { "name": "Pale Blue", "hex": "#AFEEEE" }, { "name": "Pale Brown", "hex": "#987654" }, { "name": "Pale Carmine", "hex": "#AF4035" }, { "name": "Pale Cerulean", "hex": "#9BC4E2" }, { "name": "Pale Chestnut", "hex": "#DDADAF" }, { "name": "Pale Copper", "hex": "#DA8A67" }, { "name": "Pale Cornflower Blue", "hex": "#ABCDEF" }, { "name": "Pale Cyan", "hex": "#87D3F8" }, { "name": "Pale Gold", "hex": "#E6BE8A" }, { "name": "Pale Goldenrod", "hex": "#EEE8AA" }, { "name": "Pale Green", "hex": "#98FB98" }, { "name": "Pale Lavender", "hex": "#DCD0FF" }, { "name": "Pale Magenta", "hex": "#F984E5" }, { "name": "Pale Magenta-Pink", "hex": "#FF99CC" }, { "name": "Pale Pink", "hex": "#FADADD" }, { "name": "Pale Plum", "hex": "#DDA0DD" }, { "name": "Pale Red-Violet", "hex": "#DB7093" }, { "name": "Pale Robin Egg Blue", "hex": "#96DED1" }, { "name": "Pale Silver", "hex": "#C9C0BB" }, { "name": "Pale Spring Bud", "hex": "#ECEBBD" }, { "name": "Pale Taupe", "hex": "#BC987E" }, { "name": "Pale Turquoise", "hex": "#AFEEEE" }, { "name": "Pale Violet", "hex": "#CC99FF" }, { "name": "Pale Violet-Red", "hex": "#DB7093" }, { "name": "Palm Leaf", "hex": "#6F9940" }, { "name": "Pansy Purple", "hex": "#78184A" }, { "name": "Paolo Veronese Green", "hex": "#009B7D" }, { "name": "Papaya Whip", "hex": "#FFEFD5" }, { "name": "Paradise Pink", "hex": "#E63E62" }, { "name": "Paris Green", "hex": "#50C878" }, { "name": "Parrot Pink", "hex": "#D998A0" }, { "name": "Pastel Blue", "hex": "#AEC6CF" }, { "name": "Pastel Brown", "hex": "#836953" }, { "name": "Pastel Gray", "hex": "#CFCFC4" }, { "name": "Pastel Green", "hex": "#77DD77" }, { "name": "Pastel Magenta", "hex": "#F49AC2" }, { "name": "Pastel Orange", "hex": "#FFB347" }, { "name": "Pastel Pink", "hex": "#DEA5A4" }, { "name": "Pastel Purple", "hex": "#B39EB5" }, { "name": "Pastel Red", "hex": "#FF6961" }, { "name": "Pastel Violet", "hex": "#CB99C9" }, { "name": "Pastel Yellow", "hex": "#FDFD96" }, { "name": "Patriarch", "hex": "#800080" }, { "name": "Payne's Grey", "hex": "#536878" }, { "name": "Peach", "hex": "#FFE5B4" }, { "name": "Peach", "hex": "#FFCBA4" }, { "name": "Peach-Orange", "hex": "#FFCC99" }, { "name": "Peach Puff", "hex": "#FFDAB9" }, { "name": "Peach-Yellow", "hex": "#FADFAD" }, { "name": "Pear", "hex": "#D1E231" }, { "name": "Pearl", "hex": "#EAE0C8" }, { "name": "Pearl Aqua", "hex": "#88D8C0" }, { "name": "Pearly Purple", "hex": "#B768A2" }, { "name": "Peridot", "hex": "#E6E200" }, { "name": "Periwinkle", "hex": "#CCCCFF" }, { "name": "Permanent Geranium Lake", "hex": "#E12C2C" }, { "name": "Persian Blue", "hex": "#1C39BB" }, { "name": "Persian Green", "hex": "#00A693" }, { "name": "Persian Indigo", "hex": "#32127A" }, { "name": "Persian Orange", "hex": "#D99058" }, { "name": "Persian Pink", "hex": "#F77FBE" }, { "name": "Persian Plum", "hex": "#701C1C" }, { "name": "Persian Red", "hex": "#CC3333" }, { "name": "Persian Rose", "hex": "#FE28A2" }, { "name": "Persimmon", "hex": "#EC5800" }, { "name": "Peru", "hex": "#CD853F" }, { "name": "Pewter Blue", "hex": "#8BA8B7" }, { "name": "Phlox", "hex": "#DF00FF" }, { "name": "Phthalo Blue", "hex": "#000F89" }, { "name": "Phthalo Green", "hex": "#123524" }, { "name": "Picton Blue", "hex": "#45B1E8" }, { "name": "Pictorial Carmine", "hex": "#C30B4E" }, { "name": "Piggy Pink", "hex": "#FDDDE6" }, { "name": "Pine Green", "hex": "#01796F" }, { "name": "Pineapple", "hex": "#563C0D" }, { "name": "Pink", "hex": "#FFC0CB" }, { "name": "Pink (Pantone)", "hex": "#D74894" }, { "name": "Pink Flamingo", "hex": "#FC74FD" }, { "name": "Pink Lace", "hex": "#FFDDF4" }, { "name": "Pink Lavender", "hex": "#D8B2D1" }, { "name": "Pink-Orange", "hex": "#FF9966" }, { "name": "Pink Pearl", "hex": "#E7ACCF" }, { "name": "Pink Raspberry", "hex": "#980036" }, { "name": "Pink Sherbet", "hex": "#F78FA7" }, { "name": "Pistachio", "hex": "#93C572" }, { "name": "Pixie Powder", "hex": "#391285" }, { "name": "Platinum", "hex": "#E5E4E2" }, { "name": "Plum", "hex": "#8E4585" }, { "name": "Plum (Web)", "hex": "#DDA0DD" }, { "name": "Plump Purple", "hex": "#5946B2" }, { "name": "Polished Pine", "hex": "#5DA493" }, { "name": "Pomp And Power", "hex": "#86608E" }, { "name": "Popstar", "hex": "#BE4F62" }, { "name": "Portland Orange", "hex": "#FF5A36" }, { "name": "Powder Blue", "hex": "#B0E0E6" }, { "name": "Princess Perfume", "hex": "#FF85CF" }, { "name": "Princeton Orange", "hex": "#F58025" }, { "name": "Prune", "hex": "#701C1C" }, { "name": "Prussian Blue", "hex": "#003153" }, { "name": "Psychedelic Purple", "hex": "#DF00FF" }, { "name": "Puce", "hex": "#CC8899" }, { "name": "Puce Red", "hex": "#722F37" }, { "name": "Pullman Brown (UPS Brown)", "hex": "#644117" }, { "name": "Pullman Green", "hex": "#3B331C" }, { "name": "Pumpkin", "hex": "#FF7518" }, { "name": "Purple (HTML)", "hex": "#800080" }, { "name": "Purple (Munsell)", "hex": "#9F00C5" }, { "name": "Purple (X11)", "hex": "#A020F0" }, { "name": "Purple Heart", "hex": "#69359C" }, { "name": "Purple Mountain Majesty", "hex": "#9678B6" }, { "name": "Purple Navy", "hex": "#4E5180" }, { "name": "Purple Pizzazz", "hex": "#FE4EDA" }, { "name": "Purple Plum", "hex": "#9C51B6" }, { "name": "Purple Taupe", "hex": "#50404D" }, { "name": "Purpureus", "hex": "#9A4EAE" }, { "name": "Quartz", "hex": "#51484F" }, { "name": "Queen Blue", "hex": "#436B95" }, { "name": "Queen Pink", "hex": "#E8CCD7" }, { "name": "Quick Silver", "hex": "#A6A6A6" }, { "name": "Quinacridone Magenta", "hex": "#8E3A59" }, { "name": "Rackley", "hex": "#5D8AA8" }, { "name": "Radical Red", "hex": "#FF355E" }, { "name": "Raisin Black", "hex": "#242124" }, { "name": "Rajah", "hex": "#FBAB60" }, { "name": "Raspberry", "hex": "#E30B5D" }, { "name": "Raspberry Glace", "hex": "#915F6D" }, { "name": "Raspberry Pink", "hex": "#E25098" }, { "name": "Raspberry Rose", "hex": "#B3446C" }, { "name": "Raw Sienna", "hex": "#D68A59" }, { "name": "Raw Umber", "hex": "#826644" }, { "name": "Razzle Dazzle Rose", "hex": "#FF33CC" }, { "name": "Razzmatazz", "hex": "#E3256B" }, { "name": "Razzmic Berry", "hex": "#8D4E85" }, { "name": "Rebecca Purple", "hex": "#663399" }, { "name": "Red", "hex": "#FF0000" }, { "name": "Red (Crayola)", "hex": "#EE204D" }, { "name": "Red (Munsell)", "hex": "#F2003C" }, { "name": "Red (NCS)", "hex": "#C40233" }, { "name": "Red (Pantone)", "hex": "#ED2939" }, { "name": "Red (Pigment)", "hex": "#ED1C24" }, { "name": "Red (RYB)", "hex": "#FE2712" }, { "name": "Red-Brown", "hex": "#A52A2A" }, { "name": "Red Devil", "hex": "#860111" }, { "name": "Red-Orange", "hex": "#FF5349" }, { "name": "Red-Purple", "hex": "#E40078" }, { "name": "Red Salsa", "hex": "#FD3A4A" }, { "name": "Red-Violet", "hex": "#C71585" }, { "name": "Redwood", "hex": "#A45A52" }, { "name": "Regalia", "hex": "#522D80" }, { "name": "Registration Black", "hex": "#000000" }, { "name": "Resolution Blue", "hex": "#002387" }, { "name": "Rhythm", "hex": "#777696" }, { "name": "Rich Black", "hex": "#004040" }, { "name": "Rich Black (FOGRA29)", "hex": "#010B13" }, { "name": "Rich Black (FOGRA39)", "hex": "#010203" }, { "name": "Rich Brilliant Lavender", "hex": "#F1A7FE" }, { "name": "Rich Carmine", "hex": "#D70040" }, { "name": "Rich Electric Blue", "hex": "#0892D0" }, { "name": "Rich Lavender", "hex": "#A76BCF" }, { "name": "Rich Lilac", "hex": "#B666D2" }, { "name": "Rich Maroon", "hex": "#B03060" }, { "name": "Rifle Green", "hex": "#444C38" }, { "name": "Roast Coffee", "hex": "#704241" }, { "name": "Robin Egg Blue", "hex": "#00CCCC" }, { "name": "Rocket Metallic", "hex": "#8A7F80" }, { "name": "Roman Silver", "hex": "#838996" }, { "name": "Rose", "hex": "#FF007F" }, { "name": "Rose Bonbon", "hex": "#F9429E" }, { "name": "Rose Dust", "hex": "#9E5E6F" }, { "name": "Rose Ebony", "hex": "#674846" }, { "name": "Rose Gold", "hex": "#B76E79" }, { "name": "Rose Madder", "hex": "#E32636" }, { "name": "Rose Pink", "hex": "#FF66CC" }, { "name": "Rose Quartz", "hex": "#AA98A9" }, { "name": "Rose Red", "hex": "#C21E56" }, { "name": "Rose Taupe", "hex": "#905D5D" }, { "name": "Rose Vale", "hex": "#AB4E52" }, { "name": "Rosewood", "hex": "#65000B" }, { "name": "Rosso Corsa", "hex": "#D40000" }, { "name": "Rosy Brown", "hex": "#BC8F8F" }, { "name": "Royal Azure", "hex": "#0038A8" }, { "name": "Royal Blue", "hex": "#002366" }, { "name": "Royal Blue", "hex": "#4169E1" }, { "name": "Royal Fuchsia", "hex": "#CA2C92" }, { "name": "Royal Purple", "hex": "#7851A9" }, { "name": "Royal Yellow", "hex": "#FADA5E" }, { "name": "Ruber", "hex": "#CE4676" }, { "name": "Rubine Red", "hex": "#D10056" }, { "name": "Ruby", "hex": "#E0115F" }, { "name": "Ruby Red", "hex": "#9B111E" }, { "name": "Ruddy", "hex": "#FF0028" }, { "name": "Ruddy Brown", "hex": "#BB6528" }, { "name": "Ruddy Pink", "hex": "#E18E96" }, { "name": "Rufous", "hex": "#A81C07" }, { "name": "Russet", "hex": "#80461B" }, { "name": "Russian Green", "hex": "#679267" }, { "name": "Russian Violet", "hex": "#32174D" }, { "name": "Rust", "hex": "#B7410E" }, { "name": "Rusty Red", "hex": "#DA2C43" }, { "name": "Sacramento State Green", "hex": "#00563F" }, { "name": "Saddle Brown", "hex": "#8B4513" }, { "name": "Safety Orange", "hex": "#FF7800" }, { "name": "Safety Orange (Blaze Orange)", "hex": "#FF6700" }, { "name": "Safety Yellow", "hex": "#EED202" }, { "name": "Saffron", "hex": "#F4C430" }, { "name": "Sage", "hex": "#BCB88A" }, { "name": "St. Patrick's Blue", "hex": "#23297A" }, { "name": "Salmon", "hex": "#FA8072" }, { "name": "Salmon Pink", "hex": "#FF91A4" }, { "name": "Sand", "hex": "#C2B280" }, { "name": "Sand Dune", "hex": "#967117" }, { "name": "Sandstorm", "hex": "#ECD540" }, { "name": "Sandy Brown", "hex": "#F4A460" }, { "name": "Sandy Tan", "hex": "#FDD9B5" }, { "name": "Sandy Taupe", "hex": "#967117" }, { "name": "Sangria", "hex": "#92000A" }, { "name": "Sap Green", "hex": "#507D2A" }, { "name": "Sapphire", "hex": "#0F52BA" }, { "name": "Sapphire Blue", "hex": "#0067A5" }, { "name": "Sasquatch Socks", "hex": "#FF4681" }, { "name": "Satin Sheen Gold", "hex": "#CBA135" }, { "name": "Scarlet", "hex": "#FF2400" }, { "name": "Scarlet", "hex": "#FD0E35" }, { "name": "Schauss Pink", "hex": "#FF91AF" }, { "name": "School Bus Yellow", "hex": "#FFD800" }, { "name": "Screamin' Green", "hex": "#66FF66" }, { "name": "Sea Blue", "hex": "#006994" }, { "name": "Sea Foam Green", "hex": "#9FE2BF" }, { "name": "Sea Green", "hex": "#2E8B57" }, { "name": "Sea Serpent", "hex": "#4BC7CF" }, { "name": "Seal Brown", "hex": "#59260B" }, { "name": "Seashell", "hex": "#FFF5EE" }, { "name": "Selective Yellow", "hex": "#FFBA00" }, { "name": "Sepia", "hex": "#704214" }, { "name": "Shadow", "hex": "#8A795D" }, { "name": "Shadow Blue", "hex": "#778BA5" }, { "name": "Shampoo", "hex": "#FFCFF1" }, { "name": "Shamrock Green", "hex": "#009E60" }, { "name": "Sheen Green", "hex": "#8FD400" }, { "name": "Shimmering Blush", "hex": "#D98695" }, { "name": "Shiny Shamrock", "hex": "#5FA778" }, { "name": "Shocking Pink", "hex": "#FC0FC0" }, { "name": "Shocking Pink (Crayola)", "hex": "#FF6FFF" }, { "name": "Sienna", "hex": "#882D17" }, { "name": "Silver", "hex": "#C0C0C0" }, { "name": "Silver Chalice", "hex": "#ACACAC" }, { "name": "Silver Lake Blue", "hex": "#5D89BA" }, { "name": "Silver Pink", "hex": "#C4AEAD" }, { "name": "Silver Sand", "hex": "#BFC1C2" }, { "name": "Sinopia", "hex": "#CB410B" }, { "name": "Sizzling Red", "hex": "#FF3855" }, { "name": "Sizzling Sunrise", "hex": "#FFDB00" }, { "name": "Skobeloff", "hex": "#007474" }, { "name": "Sky Blue", "hex": "#87CEEB" }, { "name": "Sky Magenta", "hex": "#CF71AF" }, { "name": "Slate Blue", "hex": "#6A5ACD" }, { "name": "Slate Gray", "hex": "#708090" }, { "name": "Smalt (Dark Powder Blue)", "hex": "#003399" }, { "name": "Slimy Green", "hex": "#299617" }, { "name": "Smashed Pumpkin", "hex": "#FF6D3A" }, { "name": "Smitten", "hex": "#C84186" }, { "name": "Smoke", "hex": "#738276" }, { "name": "Smokey Topaz", "hex": "#832A0D" }, { "name": "Smoky Black", "hex": "#100C08" }, { "name": "Smoky Topaz", "hex": "#933D41" }, { "name": "Snow", "hex": "#FFFAFA" }, { "name": "Soap", "hex": "#CEC8EF" }, { "name": "Solid Pink", "hex": "#893843" }, { "name": "Sonic Silver", "hex": "#757575" }, { "name": "Spartan Crimson", "hex": "#9E1316" }, { "name": "Space Cadet", "hex": "#1D2951" }, { "name": "Spanish Bistre", "hex": "#807532" }, { "name": "Spanish Blue", "hex": "#0070B8" }, { "name": "Spanish Carmine", "hex": "#D10047" }, { "name": "Spanish Crimson", "hex": "#E51A4C" }, { "name": "Spanish Gray", "hex": "#989898" }, { "name": "Spanish Green", "hex": "#009150" }, { "name": "Spanish Orange", "hex": "#E86100" }, { "name": "Spanish Pink", "hex": "#F7BFBE" }, { "name": "Spanish Red", "hex": "#E60026" }, { "name": "Spanish Sky Blue", "hex": "#00FFFF" }, { "name": "Spanish Violet", "hex": "#4C2882" }, { "name": "Spanish Viridian", "hex": "#007F5C" }, { "name": "Spicy Mix", "hex": "#8B5f4D" }, { "name": "Spiro Disco Ball", "hex": "#0FC0FC" }, { "name": "Spring Bud", "hex": "#A7FC00" }, { "name": "Spring Frost", "hex": "#87FF2A" }, { "name": "Spring Green", "hex": "#00FF7F" }, { "name": "Star Command Blue", "hex": "#007BB8" }, { "name": "Steel Blue", "hex": "#4682B4" }, { "name": "Steel Pink", "hex": "#CC33CC" }, { "name": "Steel Teal", "hex": "#5F8A8B" }, { "name": "Stil De Grain Yellow", "hex": "#FADA5E" }, { "name": "Stizza", "hex": "#990000" }, { "name": "Stormcloud", "hex": "#4F666A" }, { "name": "Straw", "hex": "#E4D96F" }, { "name": "Strawberry", "hex": "#FC5A8D" }, { "name": "Sugar Plum", "hex": "#914E75" }, { "name": "Sunburnt Cyclops", "hex": "#FF404C" }, { "name": "Sunglow", "hex": "#FFCC33" }, { "name": "Sunny", "hex": "#F2F27A" }, { "name": "Sunray", "hex": "#E3AB57" }, { "name": "Sunset", "hex": "#FAD6A5" }, { "name": "Sunset Orange", "hex": "#FD5E53" }, { "name": "Super Pink", "hex": "#CF6BA9" }, { "name": "Sweet Brown", "hex": "#A83731" }, { "name": "Tan", "hex": "#D2B48C" }, { "name": "Tangelo", "hex": "#F94D00" }, { "name": "Tangerine", "hex": "#F28500" }, { "name": "Tangerine Yellow", "hex": "#FFCC00" }, { "name": "Tango Pink", "hex": "#E4717A" }, { "name": "Tart Orange", "hex": "#FB4D46" }, { "name": "Taupe", "hex": "#483C32" }, { "name": "Taupe Gray", "hex": "#8B8589" }, { "name": "Tea Green", "hex": "#D0F0C0" }, { "name": "Tea Rose", "hex": "#F88379" }, { "name": "Tea Rose", "hex": "#F4C2C2" }, { "name": "Teal", "hex": "#008080" }, { "name": "Teal Blue", "hex": "#367588" }, { "name": "Teal Deer", "hex": "#99E6B3" }, { "name": "Teal Green", "hex": "#00827F" }, { "name": "Telemagenta", "hex": "#CF3476" }, { "name": "Tenne (Tawny)", "hex": "#CD5700" }, { "name": "Terra Cotta", "hex": "#E2725B" }, { "name": "Thistle", "hex": "#D8BFD8" }, { "name": "Thulian Pink", "hex": "#DE6FA1" }, { "name": "Tickle Me Pink", "hex": "#FC89AC" }, { "name": "Tiffany Blue", "hex": "#0ABAB5" }, { "name": "Tiger's Eye", "hex": "#E08D3C" }, { "name": "Timberwolf", "hex": "#DBD7D2" }, { "name": "Titanium Yellow", "hex": "#EEE600" }, { "name": "Tomato", "hex": "#FF6347" }, { "name": "Toolbox", "hex": "#746CC0" }, { "name": "Topaz", "hex": "#FFC87C" }, { "name": "Tractor Red", "hex": "#FD0E35" }, { "name": "Trolley Grey", "hex": "#808080" }, { "name": "Tropical Rain Forest", "hex": "#00755E" }, { "name": "Tropical Violet", "hex": "#CDA4DE" }, { "name": "True Blue", "hex": "#0073CF" }, { "name": "Tufts Blue", "hex": "#3E8EDE" }, { "name": "Tulip", "hex": "#FF878D" }, { "name": "Tumbleweed", "hex": "#DEAA88" }, { "name": "Turkish Rose", "hex": "#B57281" }, { "name": "Turquoise", "hex": "#40E0D0" }, { "name": "Turquoise Blue", "hex": "#00FFEF" }, { "name": "Turquoise Green", "hex": "#A0D6B4" }, { "name": "Turquoise Surf", "hex": "#00C5CD" }, { "name": "Turtle Green", "hex": "#8A9A5B" }, { "name": "Tuscan", "hex": "#FAD6A5" }, { "name": "Tuscan Brown", "hex": "#6F4E37" }, { "name": "Tuscan Red", "hex": "#7C4848" }, { "name": "Tuscan Tan", "hex": "#A67B5B" }, { "name": "Tuscany", "hex": "#C09999" }, { "name": "Twilight Lavender", "hex": "#8A496B" }, { "name": "Tyrian Purple", "hex": "#66023C" }, { "name": "UA Blue", "hex": "#0033AA" }, { "name": "UA Red", "hex": "#D9004C" }, { "name": "Ube", "hex": "#8878C3" }, { "name": "UCLA Blue", "hex": "#536895" }, { "name": "UCLA Gold", "hex": "#FFB300" }, { "name": "UFO Green", "hex": "#3CD070" }, { "name": "Ultramarine", "hex": "#3F00FF" }, { "name": "Ultramarine Blue", "hex": "#4166F5" }, { "name": "Ultra Pink", "hex": "#FF6FFF" }, { "name": "Ultra Red", "hex": "#FC6C85" }, { "name": "Umber", "hex": "#635147" }, { "name": "Unbleached Silk", "hex": "#FFDDCA" }, { "name": "United Nations Blue", "hex": "#5B92E5" }, { "name": "University Of California Gold", "hex": "#B78727" }, { "name": "Unmellow Yellow", "hex": "#FFFF66" }, { "name": "UP Forest Green", "hex": "#014421" }, { "name": "UP Maroon", "hex": "#7B1113" }, { "name": "Upsdell Red", "hex": "#AE2029" }, { "name": "Urobilin", "hex": "#E1AD21" }, { "name": "USAFA Blue", "hex": "#004F98" }, { "name": "USC Cardinal", "hex": "#990000" }, { "name": "USC Gold", "hex": "#FFCC00" }, { "name": "University Of Tennessee Orange", "hex": "#F77F00" }, { "name": "Utah Crimson", "hex": "#D3003F" }, { "name": "Van Dyke Brown", "hex": "#664228" }, { "name": "Vanilla", "hex": "#F3E5AB" }, { "name": "Vanilla Ice", "hex": "#F38FA9" }, { "name": "Vegas Gold", "hex": "#C5B358" }, { "name": "Venetian Red", "hex": "#C80815" }, { "name": "Verdigris", "hex": "#43B3AE" }, { "name": "Vermilion", "hex": "#E34234" }, { "name": "Vermilion", "hex": "#D9381E" }, { "name": "Veronica", "hex": "#A020F0" }, { "name": "Very Light Azure", "hex": "#74BBFB" }, { "name": "Very Light Blue", "hex": "#6666FF" }, { "name": "Very Light Malachite Green", "hex": "#64E986" }, { "name": "Very Light Tangelo", "hex": "#FFB077" }, { "name": "Very Pale Orange", "hex": "#FFDFBF" }, { "name": "Very Pale Yellow", "hex": "#FFFFBF" }, { "name": "Violet", "hex": "#8F00FF" }, { "name": "Violet (Color Wheel)", "hex": "#7F00FF" }, { "name": "Violet (RYB)", "hex": "#8601AF" }, { "name": "Violet (Web)", "hex": "#EE82EE" }, { "name": "Violet-Blue", "hex": "#324AB2" }, { "name": "Violet-Red", "hex": "#F75394" }, { "name": "Viridian", "hex": "#40826D" }, { "name": "Viridian Green", "hex": "#009698" }, { "name": "Vista Blue", "hex": "#7C9ED9" }, { "name": "Vivid Amber", "hex": "#CC9900" }, { "name": "Vivid Auburn", "hex": "#922724" }, { "name": "Vivid Burgundy", "hex": "#9F1D35" }, { "name": "Vivid Cerise", "hex": "#DA1D81" }, { "name": "Vivid Cerulean", "hex": "#00AAEE" }, { "name": "Vivid Crimson", "hex": "#CC0033" }, { "name": "Vivid Gamboge", "hex": "#FF9900" }, { "name": "Vivid Lime Green", "hex": "#A6D608" }, { "name": "Vivid Malachite", "hex": "#00CC33" }, { "name": "Vivid Mulberry", "hex": "#B80CE3" }, { "name": "Vivid Orange", "hex": "#FF5F00" }, { "name": "Vivid Orange Peel", "hex": "#FFA000" }, { "name": "Vivid Orchid", "hex": "#CC00FF" }, { "name": "Vivid Raspberry", "hex": "#FF006C" }, { "name": "Vivid Red", "hex": "#F70D1A" }, { "name": "Vivid Red-Tangelo", "hex": "#DF6124" }, { "name": "Vivid Sky Blue", "hex": "#00CCFF" }, { "name": "Vivid Tangelo", "hex": "#F07427" }, { "name": "Vivid Tangerine", "hex": "#FFA089" }, { "name": "Vivid Vermilion", "hex": "#E56024" }, { "name": "Vivid Violet", "hex": "#9F00FF" }, { "name": "Vivid Yellow", "hex": "#FFE302" }, { "name": "Volt", "hex": "#CEFF00" }, { "name": "Wageningen Green", "hex": "#34B233" }, { "name": "Warm Black", "hex": "#004242" }, { "name": "Waterspout", "hex": "#A4F4F9" }, { "name": "Weldon Blue", "hex": "#7C98AB" }, { "name": "Wenge", "hex": "#645452" }, { "name": "Wheat", "hex": "#F5DEB3" }, { "name": "White", "hex": "#FFFFFF" }, { "name": "White Smoke", "hex": "#F5F5F5" }, { "name": "Wild Blue Yonder", "hex": "#A2ADD0" }, { "name": "Wild Orchid", "hex": "#D470A2" }, { "name": "Wild Strawberry", "hex": "#FF43A4" }, { "name": "Wild Watermelon", "hex": "#FC6C85" }, { "name": "Willpower Orange", "hex": "#FD5800" }, { "name": "Windsor Tan", "hex": "#A75502" }, { "name": "Wine", "hex": "#722F37" }, { "name": "Wine Dregs", "hex": "#673147" }, { "name": "Winter Sky", "hex": "#FF007C" }, { "name": "Winter Wizard", "hex": "#A0E6FF" }, { "name": "Wintergreen Dream", "hex": "#56887D" }, { "name": "Wisteria", "hex": "#C9A0DC" }, { "name": "Wood Brown", "hex": "#C19A6B" }, { "name": "Xanadu", "hex": "#738678" }, { "name": "Yale Blue", "hex": "#0F4D92" }, { "name": "Yankees Blue", "hex": "#1C2841" }, { "name": "Yellow", "hex": "#FFFF00" }, { "name": "Yellow (Crayola)", "hex": "#FCE883" }, { "name": "Yellow (Munsell)", "hex": "#EFCC00" }, { "name": "Yellow (NCS)", "hex": "#FFD300" }, { "name": "Yellow (Pantone)", "hex": "#FEDF00" }, { "name": "Yellow (Process)", "hex": "#FFEF00" }, { "name": "Yellow (RYB)", "hex": "#FEFE33" }, { "name": "Yellow-Green", "hex": "#9ACD32" }, { "name": "Yellow Orange", "hex": "#FFAE42" }, { "name": "Yellow Rose", "hex": "#FFF000" }, { "name": "Yellow Sunshine", "hex": "#FFF700" }, { "name": "Zaffre", "hex": "#0014A8" }, { "name": "Zinnwaldite Brown", "hex": "#2C1608" }, { "name": "Zomp", "hex": "#39A78E" } ]` ================================================ FILE: core/database/entity/database.go ================================================ package entity type DatabaseMetadata struct { Databases []Database `json:"databases"` } type Database struct { Name string `json:"name"` Tables []DatabaseTable `json:"tables"` } type DatabaseTable struct { Name string `json:"name"` Columns []DatabaseColumn `json:"columns"` Indexes []DatabaseIndex `json:"indexes"` } type DatabaseColumn struct { Name string `json:"name"` Type string `json:"type"` Primary bool `json:"primary,omitempty"` NotNull bool `json:"not_null,omitempty"` Key string `json:"key,omitempty"` Default string `json:"default,omitempty"` Extra string `json:"extra,omitempty"` AutoIncrement bool `json:"auto_increment,omitempty"` Children []DatabaseColumn `json:"children,omitempty"` Hash string `json:"hash,omitempty"` OriginalName string `json:"original_name,omitempty"` Status string `json:"status,omitempty"` } type DatabaseIndex struct { Name string `json:"name"` Type string `json:"type,omitempty"` Columns []DatabaseIndexColumn `json:"columns"` Unique bool `json:"unique"` Hash string `json:"hash,omitempty"` OriginalName string `json:"original_name,omitempty"` Status string `json:"status,omitempty"` } type DatabaseIndexColumn struct { Name string `json:"name"` Order int `json:"order"` } func (col *DatabaseIndexColumn) OrderString() string { if col.Order < 0 { return "DESC" } else { return "ASC" } } type DatabaseQueryResults struct { Columns []DatabaseColumn `json:"columns,omitempty"` Rows []map[string]interface{} `json:"rows,omitempty"` Output string `json:"output,omitempty"` Error string `json:"error,omitempty"` } ================================================ FILE: core/database/interfaces/database_registry_service.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type DatabaseRegistryService interface { Start() CheckStatus() GetDatabaseService(id primitive.ObjectID) (res DatabaseService, err error) } ================================================ FILE: core/database/interfaces/database_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/core/database/entity" "github.com/crawlab-team/crawlab/core/models/models/v2" "go.mongodb.org/mongo-driver/bson/primitive" ) type DatabaseService interface { TestConnection(id primitive.ObjectID) (err error) GetMetadata(id primitive.ObjectID) (m *entity.DatabaseMetadata, err error) GetMetadataAllDb(id primitive.ObjectID) (m *entity.DatabaseMetadata, err error) CreateDatabase(id primitive.ObjectID, databaseName string) (err error) DropDatabase(id primitive.ObjectID, databaseName string) (err error) GetTableMetadata(id primitive.ObjectID, databaseName, tableName string) (table *entity.DatabaseTable, err error) CreateTable(id primitive.ObjectID, databaseName string, table *entity.DatabaseTable) (err error) ModifyTable(id primitive.ObjectID, databaseName string, table *entity.DatabaseTable) (err error) DropTable(id primitive.ObjectID, databaseName, tableName string) (err error) RenameTable(id primitive.ObjectID, databaseName, oldTableName, newTableName string) (err error) GetColumnTypes(query string) (types []string) ReadRows(id primitive.ObjectID, databaseName, tableName string, filter map[string]interface{}, skip, limit int) ([]map[string]interface{}, int64, error) CreateRow(id primitive.ObjectID, databaseName, tableName string, row map[string]interface{}) error UpdateRow(id primitive.ObjectID, databaseName, tableName string, filter map[string]interface{}, update map[string]interface{}) error DeleteRow(id primitive.ObjectID, databaseName, tableName string, filter map[string]interface{}) error Query(id primitive.ObjectID, databaseName, query string) (results *entity.DatabaseQueryResults, err error) GetCurrentMetric(id primitive.ObjectID) (m *models.DatabaseMetricV2, err error) } ================================================ FILE: core/database/registry_service.go ================================================ package database import ( "github.com/crawlab-team/crawlab/core/database/interfaces" ) var serviceInstance interfaces.DatabaseRegistryService func SetDatabaseRegistryService(svc interfaces.DatabaseRegistryService) { serviceInstance = svc } func GetDatabaseRegistryService() interfaces.DatabaseRegistryService { return serviceInstance } ================================================ FILE: core/docker-compose.yml ================================================ version: '3.3' services: mongo: image: mongo:latest container_name: mongo restart: always ports: - "27017:27017" redis: image: redis:latest container_name: redis restart: always ports: - "6379:6379" ================================================ FILE: core/docs/.gitignore ================================================ .idea node_modules dist build tmp yarn.lock ================================================ FILE: core/docs/api/index.html ================================================ ================================================ FILE: core/docs/api/openapi.yaml ================================================ openapi: 3.0.0 info: title: Crawlab API version: 0.6.0 description: Crawlab API license: name: BSD-3-Clause url: https://github.com/crawlab-team/crawlab-pro/blob/main/LICENSE servers: - url: http://localhost:8000 description: Local API - url: http://localhost:8080/api description: Docker API - url: https://demo-pro.crawlab.cn/api description: Demo API tags: - name: login description: Login related x-displayName: Login - name: version description: Version related x-displayName: Version - name: node description: Node related x-displayName: Node - name: project description: Project related x-displayName: Project x-tagGroups: - name: Anomalous tags: - login - version - name: Auth Required tags: - node - project paths: # login /login: post: tags: [ login ] operationId: postLogin summary: Login requestBody: content: application/json: schema: type: object properties: username: type: string password: type: string example: username: admin password: admin responses: 200: description: Login successful content: application/json: schema: $ref: '#/components/schemas/PostLoginResponse' 401: description: Login failed content: application/json: schema: $ref: '#/components/schemas/UnauthorizedErrorResponse' /logout: post: tags: [ login ] operationId: postLogout summary: Logout responses: 200: description: Logout successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' # version /version: get: tags: [ version ] operationId: getVersion summary: Get version responses: 200: description: Get version successful content: application/json: schema: $ref: '#/components/schemas/GetVersionResponse' example: status: ok data: v0.6.0 # node /nodes: get: tags: [ node ] operationId: getNodes summary: Get nodes security: - apiToken: [ ] parameters: - in: query name: page description: Page number required: false schema: type: integer default: 1 - in: query name: page_size description: Page size required: false schema: type: integer default: 10 responses: 200: description: Get nodes successful content: application/json: schema: $ref: '#/components/schemas/GetNodesResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ node ] operationId: putNode summary: Update node security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayloadWithStringData' responses: 200: description: Update node successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ node ] operationId: deleteNodes summary: Delete nodes security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayload' responses: 200: description: Delete node successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /nodes/{id}: get: tags: [ node ] operationId: getNode summary: Get node security: - apiToken: [ ] parameters: - name: id in: path description: Node ID required: true schema: type: string responses: 200: description: Get node successful content: application/json: schema: $ref: '#/components/schemas/GetNodeResponse' 404: description: Node not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ node ] operationId: putNode summary: Update node security: - apiToken: [ ] parameters: - name: id in: path description: Node ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/Node' responses: 200: description: Update node successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Node not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # project /projects: get: tags: [ project ] operationId: getProjects summary: Get projects security: - apiToken: [ ] parameters: - in: query name: page schema: type: integer - in: query name: size schema: type: integer responses: 200: description: Get projects successful content: application/json: schema: $ref: '#/components/schemas/GetProjectsResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ project ] operationId: postProject summary: Create project security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostProjectRequest' responses: 200: description: Create project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ project ] operationId: putProjects summary: Update projects security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayloadWithStringData' responses: 200: description: Update project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Project not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ project ] operationId: deleteProjects summary: Delete projects security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayload' responses: 200: description: Delete project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Project not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /projects/batch: post: tags: [ project ] operationId: postProjects summary: Create projects security: - apiToken: [ ] requestBody: content: application/json: schema: type: array items: $ref: '#/components/schemas/PostProjectRequest' responses: 200: description: Update project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /projects/{id}: get: tags: [ project ] operationId: getProject summary: Get project security: - apiToken: [ ] parameters: - name: id in: path description: Project ID required: true schema: type: string responses: 200: description: Get project successful content: application/json: schema: $ref: '#/components/schemas/GetProjectResponse' 404: description: Project not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ project ] operationId: postProject summary: Update project security: - apiToken: [ ] parameters: - name: id in: path description: Project ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/Project' responses: 200: description: Update project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Project not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ project ] operationId: deleteProject summary: Delete project security: - apiToken: [ ] parameters: - name: id in: path description: Project ID required: true schema: type: string responses: 200: description: Delete project successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Project not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # spider /spiders: get: tags: [ spider ] operationId: getSpiders summary: Get spiders security: - apiToken: [ ] parameters: - in: query name: page schema: type: integer - in: query name: size schema: type: integer responses: 200: description: Get spiders successful content: application/json: schema: $ref: '#/components/schemas/GetSpidersResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ spider ] operationId: postSpiders summary: Create spiders security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayloadWithStringData' responses: 200: description: Create spiders successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/batch: post: tags: [ spider ] operationId: postSpiders summary: Update spiders security: - apiToken: [ ] requestBody: content: application/json: schema: type: array items: $ref: '#/components/schemas/PostSpiderRequest' responses: 200: description: Update spiders successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}: get: tags: [ spider ] operationId: getSpider summary: Get spider security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string responses: 200: description: Get spider successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ spider ] operationId: postSpider summary: Update spider security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/Spider' responses: 200: description: Update spider successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ spider ] operationId: deleteSpider summary: Delete spider security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string /spiders/{id}/files/list: get: tags: [ spider ] operationId: getSpiderFilesList summary: Get spider files list security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string responses: 200: description: Get spider files list successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderFilesListResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/get: get: tags: [ spider ] operationId: getSpiderFile summary: Get spider file security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string responses: 200: description: Get spider file successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderFileResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/info: get: tags: [ spider ] operationId: getSpiderFileInfo summary: Get spider file info security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string responses: 200: description: Get spider file info successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderFileInfoResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/save: post: tags: [ spider ] operationId: postSpiderFile summary: Save spider file security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderFileRequest' responses: 200: description: Save spider file successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/save/dir: post: tags: [ spider ] operationId: postSpiderFileDir summary: Save spider file dir security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderFileDirRequest' responses: 200: description: Save spider file dir successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/renameFile: post: tags: [ spider ] operationId: postSpiderFileRenameFile summary: Rename spider file security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderFileRenameFileRequest' responses: 200: description: Rename spider file successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/delete: post: tags: [ spider ] operationId: postSpiderFileDelete summary: Delete spider file security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string responses: 200: description: Delete spider file successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/files/copy: post: tags: [ spider ] operationId: postSpiderFileCopy summary: Copy spider file security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: path in: query description: File path required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderFileCopyRequest' responses: 200: description: Copy spider file successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/run: post: tags: [ spider ] operationId: postSpiderRun summary: Run spider security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderRunRequest' responses: 200: description: Run spider successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/git: get: tags: [ spider ] operationId: getSpiderGit summary: Get spider git security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string responses: 200: description: Get spider git successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderGitResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/git/remote-refs: get: tags: [ spider ] operationId: getSpiderGitRemoteRefs summary: Get spider git remote refs security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string responses: 200: description: Get spider git remote refs successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderGitRemoteRefsResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/git/pull: post: tags: [ spider ] operationId: postSpiderGitPull summary: Pull spider git security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderGitPullRequest' responses: 200: description: Pull spider git successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/git/commit: post: tags: [ spider ] operationId: postSpiderGitCommit summary: Commit spider git security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSpiderGitCommitRequest' responses: 200: description: Commit spider git successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/data-source: get: tags: [ spider ] operationId: getSpiderDataSource summary: Get spider data source security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string responses: 200: description: Get spider data source successful content: application/json: schema: $ref: '#/components/schemas/GetSpiderDataSourceResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /spiders/{id}/data-source/{ds_id}: post: tags: [ spider ] operationId: postSpiderDataSource summary: Create spider data source security: - apiToken: [ ] parameters: - name: id in: path description: Spider ID required: true schema: type: string - name: ds_id in: path description: Data source ID required: true schema: type: string responses: 200: description: Create spider data source successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Spider not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # schedule /schedules: get: tags: [ schedule ] operationId: getSchedules summary: Get schedules security: - apiToken: [ ] parameters: - name: page in: query description: Page number required: false schema: type: integer - name: page_size in: query description: Page size required: false schema: type: integer responses: 200: description: Get schedules successful content: application/json: schema: $ref: '#/components/schemas/GetSchedulesResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ schedule ] operationId: postSchedule summary: Create schedule security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostScheduleRequest' responses: 200: description: Create schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ schedule ] operationId: putSchedule summary: Update schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayloadWithStringData' responses: 200: description: Update schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ schedule ] operationId: deleteSchedules summary: Delete schedules security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayload' responses: 200: description: Delete schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /schedules/batch: post: tags: [ schedule ] operationId: postSchedulesBatch summary: Create schedules security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostSchedulesBatchRequest' responses: 200: description: Create schedules successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /schedules/{id}: get: tags: [ schedule ] operationId: getSchedule summary: Get schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string responses: 200: description: Get schedule successful content: application/json: schema: $ref: '#/components/schemas/GetScheduleResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ schedule ] operationId: putSchedule summary: Update schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PutScheduleRequest' responses: 200: description: Update schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ schedule ] operationId: deleteSchedule summary: Delete schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string responses: 200: description: Delete schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /schedules/{id}/enabled: post: tags: [ schedule ] operationId: postScheduleEnabled summary: Enable schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string responses: 200: description: Enable schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /schedules/{id}/disabled: post: tags: [ schedule ] operationId: postScheduleDisabled summary: Disable schedule security: - apiToken: [ ] parameters: - name: id in: path description: Schedule ID required: true schema: type: string responses: 200: description: Disable schedule successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Schedule not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # task /tasks: get: tags: [ task ] operationId: getTasks summary: Get tasks security: - apiToken: [ ] parameters: - name: page in: query description: Page number required: false schema: type: integer - name: size in: query description: Page size number required: false schema: type: integer responses: 200: description: Get tasks successful content: application/json: schema: $ref: '#/components/schemas/GetTasksResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ task ] operationId: deleteTasks summary: Delete tasks security: - apiToken: [ ] parameters: - name: ids in: query description: Task IDs required: true schema: type: array items: type: string responses: 200: description: Delete tasks successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/run: post: tags: [ task ] operationId: postTaskRun summary: Run task security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostTaskRunRequest' responses: 200: description: Run task successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/{id}: get: tags: [ task ] operationId: getTask summary: Get task security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string responses: 200: description: Get task successful content: application/json: schema: $ref: '#/components/schemas/GetTaskResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ task ] operationId: deleteTask summary: Delete task security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string responses: 200: description: Delete task successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/{id}/restart: post: tags: [ task ] operationId: postTaskRestart summary: Restart task security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string responses: 200: description: Restart task successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/{id}/cancel: post: tags: [ task ] operationId: postTaskCancel summary: Cancel task security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string responses: 200: description: Cancel task successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/{id}/logs: get: tags: [ task ] operationId: getTaskLogs summary: Get task logs security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string - name: page in: query description: Page number required: false schema: type: integer - name: size in: query description: Page size number required: false schema: type: integer responses: 200: description: Get task logs successful content: application/json: schema: $ref: '#/components/schemas/GetTaskLogsResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tasks/{id}/data: get: tags: [ task ] operationId: getTaskData summary: Get task data security: - apiToken: [ ] parameters: - name: id in: path description: Task ID required: true schema: type: string - name: page in: query description: Page number required: false schema: type: integer - name: size in: query description: Page size number required: false schema: type: integer responses: 200: description: Get task data successful content: application/json: schema: $ref: '#/components/schemas/GetTaskDataResponse' 404: description: Task not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # user /users: get: tags: [ user ] operationId: getUsers summary: Get users security: - apiToken: [ ] parameters: - name: page in: query description: Page number required: false schema: type: integer example: 1 - name: size in: query description: Page size number required: false schema: type: integer example: 10 responses: 200: description: Get users successful content: application/json: schema: $ref: '#/components/schemas/GetUsersResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ user ] operationId: postUser summary: Create user security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostUserRequest' responses: 200: description: Create user successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ user ] operationId: putUser summary: Update user security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/BatchRequestPayloadWithStringData' responses: 200: description: Update user successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ user ] operationId: deleteUser summary: Delete user security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string responses: 200: description: Delete user successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /users/{id}: get: tags: [ user ] operationId: getUser summary: Get user security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string responses: 200: description: Get user successful content: application/json: schema: $ref: '#/components/schemas/GetUserResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ user ] operationId: putUser summary: Update user security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PutUserRequest' responses: 200: description: Update user successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ user ] operationId: deleteUser summary: Delete user security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string responses: 200: description: Delete user successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /users/{id}/change-password: post: tags: [ user ] operationId: changePassword summary: Change password security: - apiToken: [ ] parameters: - name: id in: path description: User ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PostUserChangePasswordRequest' responses: 200: description: Change password successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: User not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /users/me: get: tags: [ user ] operationId: getMe summary: Get me security: - apiToken: [ ] responses: 200: description: Get me successful content: application/json: schema: $ref: '#/components/schemas/GetUserResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ user ] operationId: putMe summary: Update me security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PutUserRequest' responses: 200: description: Update me successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # token /tokens: get: tags: [ token ] operationId: getTokens summary: Get tokens security: - apiToken: [ ] parameters: - name: page in: query description: Page number required: false schema: type: integer example: 1 - name: size in: query description: Page size required: false schema: type: integer example: 10 responses: 200: description: Get tokens successful content: application/json: schema: $ref: '#/components/schemas/GetTokensResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ token ] operationId: postToken summary: Create token security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostTokenRequest' responses: 200: description: Create token successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /tokens/{id}: get: tags: [ token ] operationId: getToken summary: Get token security: - apiToken: [ ] parameters: - name: id in: path description: Token ID required: true schema: type: string responses: 200: description: Get token successful content: application/json: schema: $ref: '#/components/schemas/GetTokenResponse' 404: description: Token not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' put: tags: [ token ] operationId: putToken summary: Update token security: - apiToken: [ ] parameters: - name: id in: path description: Token ID required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PutTokenRequest' responses: 200: description: Update token successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Token not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' delete: tags: [ token ] operationId: deleteToken summary: Delete token security: - apiToken: [ ] parameters: - name: id in: path description: Token ID required: true schema: type: string responses: 200: description: Delete token successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Token not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' # plugin /plugins: get: tags: [ plugin ] operationId: getPlugins summary: Get plugins security: - apiToken: [ ] parameters: - name: page in: query description: Page number required: false schema: type: integer example: 1 - name: size in: query description: Page size required: false schema: type: integer example: 10 responses: 200: description: Get plugins successful content: application/json: schema: $ref: '#/components/schemas/GetPluginsResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' post: tags: [ plugin ] operationId: postPlugin summary: Create plugin security: - apiToken: [ ] requestBody: content: application/json: schema: $ref: '#/components/schemas/PostPluginRequest' responses: 200: description: Create plugin successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /plugins/{id}: get: tags: [ plugin ] operationId: getPlugin summary: Get plugin security: - apiToken: [ ] parameters: - name: id in: path description: Plugin ID required: true schema: type: string responses: 200: description: Get plugin successful content: application/json: schema: $ref: '#/components/schemas/GetPluginResponse' 404: description: Plugin not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /plugins/{id}/start: post: tags: [ plugin ] operationId: startPlugin summary: Start plugin security: - apiToken: [ ] parameters: - name: id in: path description: Plugin ID required: true schema: type: string responses: 200: description: Start plugin successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Plugin not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /plugins/{id}/stop: post: tags: [ plugin ] operationId: stopPlugin summary: Stop plugin security: - apiToken: [ ] parameters: - name: id in: path description: Plugin ID required: true schema: type: string responses: 200: description: Stop plugin successful content: application/json: schema: $ref: '#/components/schemas/EmptyResponse' 404: description: Plugin not found content: application/json: schema: $ref: '#/components/schemas/NotFoundErrorResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /plugins/public: get: tags: [ plugin ] operationId: getPublicPlugins summary: Get public plugins security: - apiToken: [ ] responses: 200: description: Get public plugins successful content: application/json: schema: $ref: '#/components/schemas/GetPublicPluginsResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' /plugins/public/info: get: tags: [ plugin ] operationId: getPublicPluginsInfo summary: Get public plugins info security: - apiToken: [ ] parameters: - in: query name: full_name description: Plugin full name required: true schema: type: string responses: 200: description: Get public plugins info successful content: application/json: schema: $ref: '#/components/schemas/GetPublicPluginsInfoResponse' 400: description: Bad request content: application/json: schema: $ref: '#/components/schemas/BadRequestErrorResponse' components: schemas: # base request bodies BatchRequestPayload: description: Batch request payload properties: ids: type: array description: Model IDs to operate items: type: string BatchRequestPayloadWithStringData: description: Batch request payload with string data properties: ids: type: array description: Model IDs to operate items: type: string data: type: string description: JSON marshalled model fields data to operate fields: type: array description: Fields to operate items: type: string # request bodies PostProjectRequest: description: Put project request body properties: name: type: string description: Project name description: type: string description: Project description PostSpiderRequest: description: Put project request body properties: name: type: string description: Spider name description: type: string description: Spider description type: type: string description: Spider type params: type: string description: Default spider task params col_name: type: string description: Spider collection name project_id: type: string description: Spider project ID mode: type: string enum: - random - all-nodes - selected-nodes description: Default spider task mode PostSpiderFileRequest: description: Post spider file request body properties: path: type: string description: File path data: type: string description: File data PostSpiderFileDirRequest: description: Post spider file dir request body properties: path: type: string description: File path PostSpiderFileRenameFileRequest: description: Post spider file rename file request body properties: path: type: string description: File path new_path: type: string description: New file path PostSpiderFileCopyRequest: description: Post spider file copy request body properties: path: type: string description: File path new_path: type: string description: New file path PostSpiderRunRequest: description: Post spider run request body properties: params: type: string description: Spider task params mode: type: string enum: - random - all-nodes - selected-nodes description: Spider task mode example: mode: random PostSpiderGitPullRequest: description: Post spider git pull request body properties: branch: type: string description: Git branch commit: type: string description: Git commit remote: type: string description: Git remote ref: type: string description: Git ref PostSpiderGitCommitRequest: description: Post spider git commit request body $ref: '#/components/schemas/GitPayload' PostScheduleRequest: description: Post schedule request body properties: name: type: string description: Schedule name description: type: string description: Schedule description spider_id: type: string description: Schedule spider ID cron: type: string description: Cron expression cmd: type: string description: Execute Command params: type: string description: Schedule params mode: $ref: '#/components/schemas/TaskMode' PostSchedulesBatchRequest: description: Post schedules batch request body properties: data: type: array description: Schedules data items: $ref: '#/components/schemas/PostScheduleRequest' PutScheduleRequest: description: Put schedule request body properties: name: type: string description: Schedule name description: type: string description: Schedule description project_id: type: string description: Schedule project ID spider_id: type: string description: Schedule spider ID cron: type: string description: Cron expression params: type: string description: Schedule params mode: $ref: '#/components/schemas/TaskMode' PostTaskRunRequest: description: Post task run request body properties: spider_id: type: string description: Task spider ID cmd: type: string description: Task command params: type: string description: Task params mode: $ref: '#/components/schemas/TaskMode' priority: type: integer description: Task priority PostUserRequest: description: Post user request body properties: username: type: string description: User username password: type: string description: User password email: type: string description: User email role: type: string enum: - admin - user description: User role PutUserRequest: description: Put user request body properties: username: type: string description: User username email: type: string description: User email role: type: string enum: - admin - user description: User role PostUserChangePasswordRequest: description: Post user change password request body properties: password: type: string description: New password PostTokenRequest: description: Post token request body properties: name: type: string description: Token name PutTokenRequest: description: Put token request body properties: name: type: string description: Token name PostPluginRequest: description: Post plugin request body properties: name: type: string description: Plugin name full_name: type: string description: Plugin full name # base responses BaseResponse: type: object properties: status: type: string description: Status of the response message: type: string description: Message of the response EmptyResponse: description: Empty response body $ref: '#/components/schemas/BaseResponse' example: status: ok message: success Response: description: Response body allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object ListResponse: description: List response body allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: array total: type: integer ErrorResponse: description: Error response body allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: error: type: string # error response NotFoundErrorResponse: description: Not found error response body $ref: '#/components/schemas/ErrorResponse' example: status: error message: not found BadRequestErrorResponse: description: Bad request error response $ref: '#/components/schemas/ErrorResponse' example: status: error message: bad request UnauthorizedErrorResponse: description: Unauthorized error response $ref: '#/components/schemas/ErrorResponse' example: status: error message: unauthorized # success response PostLoginResponse: type: object properties: data: type: string description: API token GetVersionResponse: type: object properties: data: type: string description: Version GetNodesResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/Node' GetNodeResponse: type: object properties: data: $ref: '#/components/schemas/Node' GetProjectsResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/Project' GetProjectResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/Project' GetSpidersResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: $ref: '#/components/schemas/Spider' GetSpiderResponse: type: object properties: data: $ref: '#/components/schemas/Spider' GetSpiderFilesListResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/SpiderFile' example: { "status": "ok", "message": "success", "data": [ { "name": "scrapy_baidu", "path": "/scrapy_baidu", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu", "extension": "", "md5": "", "is_dir": true, "file_size": 0, "children": [ { "name": "spiders", "path": "/scrapy_baidu/spiders", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/spiders", "extension": "", "md5": "", "is_dir": true, "file_size": 0, "children": [ { "name": "__init__.py", "path": "/scrapy_baidu/spiders/__init__.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/spiders/__init__.py", "extension": "py", "md5": "EoqQSUWYa98Uwyno4FRZYw==", "is_dir": false, "file_size": 161, "children": null }, { "name": "baidu.py", "path": "/scrapy_baidu/spiders/baidu.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/spiders/baidu.py", "extension": "py", "md5": "AhySHuGyj88CEA1ZbUJ19g==", "is_dir": false, "file_size": 791, "children": null } ] }, { "name": "__init__.py", "path": "/scrapy_baidu/__init__.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/__init__.py", "extension": "py", "md5": "chXunH2dwinSkhpA6JnsXw==", "is_dir": false, "file_size": 1, "children": null }, { "name": "items.py", "path": "/scrapy_baidu/items.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/items.py", "extension": "py", "md5": "Zg9KIbCe1h/coLSkQcQ9Sg==", "is_dir": false, "file_size": 311, "children": null }, { "name": "middlewares.py", "path": "/scrapy_baidu/middlewares.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/middlewares.py", "extension": "py", "md5": "4FQr2+wt4ALcuRYxzjsUdQ==", "is_dir": false, "file_size": 3658, "children": null }, { "name": "pipelines.py", "path": "/scrapy_baidu/pipelines.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/pipelines.py", "extension": "py", "md5": "q8MuuuJwvuV0gcE42Mg2oQ==", "is_dir": false, "file_size": 259, "children": null }, { "name": "settings.py", "path": "/scrapy_baidu/settings.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy_baidu/settings.py", "extension": "py", "md5": "hh/13eHBaVrLNtB27duOZQ==", "is_dir": false, "file_size": 3201, "children": null } ] }, { "name": "__init__.py", "path": "/__init__.py", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/__init__.py", "extension": "py", "md5": "chXunH2dwinSkhpA6JnsXw==", "is_dir": false, "file_size": 1, "children": null }, { "name": "crawlab.json", "path": "/crawlab.json", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/crawlab.json", "extension": "json", "md5": "jQ5qto4lYSEzWNF77h11gw==", "is_dir": false, "file_size": 169, "children": null }, { "name": "scrapy.cfg", "path": "/scrapy.cfg", "full_path": "/fs/62c66a8ef9dce6fe4caa58e5/scrapy.cfg", "extension": "cfg", "md5": "UAALAu5OkhbTVtwQeFXpQA==", "is_dir": false, "file_size": 267, "children": null } ], "error": "" } GetSpiderFileResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: string description: Spider file content example: { "status": "ok", "message": "success", "data": "# Automatically created by: scrapy startproject\n#\n# For more information about the [deploy] section see:\n# https://scrapyd.readthedocs.io/en/latest/deploy.html\n\n[settings]\ndefault = scrapy_baidu.settings\n\n[deploy]\n#url = http://localhost:6800/\nproject = scrapy_baidu\n", "error": "" } GetSpiderFileInfoResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/SpiderFile' example: { "status": "ok", "message": "success", "data": { "name": "openapi.yaml", "path": "/openapi.yaml", "full_path": "/fs/62c66a8af9dce6fe4caa58e3/openapi.yaml", "extension": "yaml", "md5": "1UUumcDmYtVAUOZZNegjJA==", "is_dir": false, "file_size": 27698, "children": null }, "error": "" } GetSpiderGitResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: object description: Spider git content properties: current_branch: type: string description: Current git branch branches: type: array description: Git branches items: type: string changes: type: array description: Git changes items: $ref: '#/components/schemas/GitFileStatus' logs: type: array description: Git logs items: $ref: '#/components/schemas/GitLog' ignore: type: array description: Git ignore files items: type: string git: type: object description: Git url $ref: '#/components/schemas/Git' GetSpiderGitRemoteRefsResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: object description: Spider git remote refs properties: refs: type: array description: Git remote refs items: $ref: '#/components/schemas/GitRef' GetSpiderDataSourceResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: array description: Spider data source items: $ref: '#/components/schemas/DataSource' GetScheduleResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: array description: Schedules items: $ref: '#/components/schemas/Schedule' GetSchedulesResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: array description: Schedules items: $ref: '#/components/schemas/Schedule' GetTasksResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array description: Tasks items: $ref: '#/components/schemas/Task' GetTaskResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/Task' GetTaskLogsResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array description: Task logs items: type: string GetTaskDataResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: type: object GetUsersResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/User' example: { "status": "ok", "message": "success", "total": 1, "data": [ { "_id": "62c665fb6e54352bf1b279e2", "username": "admin", "role": "admin", "email": "" } ], "error": "" } GetUserResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/User' example: { "status": "ok", "message": "success", "data": { "_id": "62c665fb6e54352bf1b279e2", "username": "admin", "role": "admin", "email": "" }, "error": "" } GetTokensResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/Token' example: { "status": "ok", "message": "success", "total": 1, "data": [ { "_id": "62c8e9e7f23518fd080f04aa", "name": "my token", "token": "xxxxxxxxxx" } ], "error": "" } GetTokenResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/Token' example: { "status": "ok", "message": "success", "data": { "_id": "62c8e9e7f23518fd080f04aa", "name": "my token", "token": "xxxxxxxxxx" }, "error": "" } GetPluginsResponse: type: object allOf: - $ref: '#/components/schemas/ListResponse' - properties: data: type: array items: $ref: '#/components/schemas/Plugin' example: { "status": "ok", "message": "success", "total": 3, "data": [ { "_id": "62a88b02112099e6932808a8", "name": "spider-assistant", "short_name": "plugin-spider-assistant", "full_name": "crawlab-team/plugin-spider-assistant", "description": "Spider assistant plugin for Crawlab", "proto": "http", "active": false, "endpoint": "localhost:9997", "cmd": "sh ./bin/start.sh", "docker_cmd": "/app/plugins/bin/plugin-spider-assistant", "docker_dir": "/app/plugins/plugin-spider-assistant", "event_key": { "include": "^model:", "exclude": "artifact" }, "install_type": "public", "install_url": "/app/plugins/plugin-spider-assistant", "install_cmd": "", "deploy_mode": "master", "auto_start": true, "ui_components": [ { "name": "assistant", "title": "assistant.detail.tabs.title", "src": "ui/src/AssistantDetail.vue", "type": "tab", "path": "assistant", "parent_paths": [ "/spiders/:id" ] } ], "ui_sidebar_navs": [ ], "ui_assets": [ ], "lang_url": "ui/lang", "status": null }, { "_id": "62a88b04112099e6932808aa", "name": "notification", "short_name": "plugin-notification", "full_name": "crawlab-team/plugin-notification", "description": "A plugin for handling notifications", "proto": "http", "active": false, "endpoint": "localhost:39999", "cmd": "sh ./bin/start.sh", "docker_cmd": "/app/plugins/bin/plugin-notification", "docker_dir": "/app/plugins/plugin-notification", "event_key": { "include": "^model:", "exclude": "artifact" }, "install_type": "public", "install_url": "/app/plugins/plugin-notification", "install_cmd": "", "deploy_mode": "master_only", "auto_start": true, "ui_components": [ { "name": "notification-list", "title": "Notifications", "src": "ui/src/NotificationList.vue", "type": "view", "path": "notifications", "parent_paths": null }, { "name": "notification-detail", "title": "Notifications", "src": "ui/src/NotificationDetail.vue", "type": "view", "path": "notifications/:id", "parent_paths": null } ], "ui_sidebar_navs": [ { "path": "/notifications", "title": "plugins.notification.ui_sidebar_navs.title.notifications", "icon": [ "fa", "envelope" ] } ], "ui_assets": [ { "path": "ui/public/simplemde/simplemde.js", "type": "js" }, { "path": "ui/public/simplemde/simplemde.css", "type": "css" }, { "path": "ui/public/css/style.css", "type": "css" } ], "lang_url": "ui/lang", "status": null }, { "_id": "62c390ab5853635d26cf76c7", "name": "dependency", "short_name": "plugin-dependency", "full_name": "crawlab-team/plugin-dependency", "description": "A plugin for managing dependencies", "proto": "http", "active": false, "endpoint": "localhost:9998", "cmd": "sh ./bin/start.sh", "docker_cmd": "/app/plugins/bin/plugin-dependency", "docker_dir": "/app/plugins/plugin-dependency", "event_key": { "include": "^model:", "exclude": "artifact" }, "install_type": "public", "install_url": "/app/plugins/plugin-dependency", "install_cmd": "", "deploy_mode": "all", "auto_start": true, "ui_components": [ { "name": "dependency-settings", "title": "Dependencies Settings", "src": "ui/src/setting/DependencySettings.vue", "type": "view", "path": "dependencies/settings", "parent_paths": null }, { "name": "dependency-python", "title": "Dependencies Python", "src": "ui/src/python/DependencyPython.vue", "type": "view", "path": "dependencies/python", "parent_paths": null }, { "name": "dependency-node", "title": "Dependencies Node", "src": "ui/src/node/DependencyNode.vue", "type": "view", "path": "dependencies/node", "parent_paths": null }, { "name": "dependencies", "title": "ui_components.title.dependencies", "src": "ui/src/spider/DependencySpiderTab.vue", "type": "tab", "path": "dependencies", "parent_paths": [ "/spiders/:id" ] } ], "ui_sidebar_navs": [ { "path": "/dependencies", "title": "plugins.dependency.ui_sidebar_navs.title.dependencies", "icon": [ "fa", "puzzle-piece" ], "children": [ { "path": "/dependencies/python", "title": "plugins.dependency.ui_sidebar_navs.title.python", "icon": [ "fab", "python" ] }, { "path": "/dependencies/node", "title": "plugins.dependency.ui_sidebar_navs.title.node", "icon": [ "fab", "node-js" ] }, { "path": "/dependencies/settings", "title": "plugins.dependency.ui_sidebar_navs.title.settings", "icon": [ "fa", "cog" ] } ] } ], "ui_assets": [ ], "lang_url": "ui/lang", "status": null } ], "error": "" } GetPluginResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: $ref: '#/components/schemas/Plugin' GetPublicPluginsResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: array items: $ref: '#/components/schemas/PublicPlugin' GetPublicPluginsInfoResponse: type: object allOf: - $ref: '#/components/schemas/Response' - properties: data: type: array items: type: object # models Model: description: Base model type: object properties: _id: type: string description: ID of the model (MongoDB ObjectID) ModelWithNameDescription: allOf: - $ref: '#/components/schemas/Model' - properties: name: type: string description: Name of the model description: type: string description: Description of the model ModelWithKey: allOf: - $ref: '#/components/schemas/Model' - properties: key: type: string description: Key of the model Node: description: Node model type: object allOf: - $ref: '#/components/schemas/ModelWithKey' - $ref: '#/components/schemas/ModelWithNameDescription' - properties: ip: description: Node IP type: string port: description: Node port type: string mac: description: Node MAC type: string hostname: description: Node hostname type: string is_master: description: Whether the node is master type: boolean status: description: Node current status type: string enum: - online - offline enabled: description: Node enabled type: boolean active: description: Node active type: boolean active_ts: description: Node active timestamp type: string format: date-time available_runners: description: Available number of available runners of the node type: integer max_runners: description: Max number of runners of the node type: integer Project: description: Project model type: object allOf: - $ref: '#/components/schemas/ModelWithNameDescription' - properties: spiders: description: Spiders of the project type: integer TaskStat: type: object allOf: - $ref: '#/components/schemas/Model' - properties: create_ts: type: string format: date-time start_ts: type: string format: date-time end_ts: type: string format: date-time wait_duration: type: integer runtime_duration: type: integer total_duration: type: integer result_count: type: integer error_log_count: type: integer Task: type: object allOf: - $ref: '#/components/schemas/Model' - properties: spider_id: type: string status: type: string node_id: type: string cmd: type: string param: type: string error: type: string pid: description: Process ID type: integer schedule_id: type: string type: type: string mode: $ref: '#/components/schemas/TaskMode' node_ids: type: array items: type: string parent_id: type: string priority: type: integer stat: $ref: '#/components/schemas/TaskStat' has_sub: type: boolean sub_tasks: type: array items: $ref: '#/components/schemas/Task' user_id: type: string TaskMode: type: string enum: - random - all-nodes - selected-nodes SpiderStat: description: Spider stat type: object allOf: - $ref: '#/components/schemas/Model' - properties: type: description: Last task ID type: string task: description: Last task $ref: '#/components/schemas/Task' Spider: description: Spider model type: object allOf: - $ref: '#/components/schemas/ModelWithNameDescription' - properties: type: description: Spider type type: string col_id: description: Spider collection ID type: string col_name: description: Spider collection name type: string data_source_id: description: Spider data source id type: string data_source_name: description: Spider data source name type: string project_id: description: Spider project id type: string mode: description: Spider task mode $ref: '#/components/schemas/TaskMode' node_ids: description: Spider task selected node IDs type: array items: type: string stat: description: Spider stat $ref: '#/components/schemas/SpiderStat' SpiderFile: description: Spider file model type: object properties: name: description: File name type: string path: description: File path type: string full_path: description: Full file path type: string extension: description: File extension type: string md5: description: File MD5 hash type: string is_dir: description: Whether the file is directory type: string fileSize: description: File size type: integer children: description: Children files type: array items: $ref: '#/components/schemas/SpiderFile' GitFileStatus: description: Git file status type: object properties: path: description: File path type: string name: description: File name type: string is_dir: description: Whether the file is directory type: boolean staging: description: Staging type: string worktree: description: Worktree type: string extra: description: Extra type: string children: description: Children files type: array items: $ref: '#/components/schemas/GitFileStatus' GitRef: description: Git ref type: object properties: type: description: Ref type type: string name: description: Ref name type: string full_name: description: Ref full name type: string hash: description: Ref hash type: string timestamp: description: Ref timestamp type: string format: date-time GitLog: description: Git log type: object properties: hash: description: Commit hash type: string msg: description: Commit message type: string author_name: description: Author name type: string author_email: description: Author email type: string timestamp: description: Commit timestamp type: string format: date-time refs: description: Commit refs type: array items: $ref: '#/components/schemas/GitRef' Git: description: Git model type: object allOf: - $ref: '#/components/schemas/ModelWithKey' - properties: url: description: Git url type: string branch: description: Git branch type: string changes: description: Git changes type: array items: $ref: '#/components/schemas/GitFileStatus' logs: description: Git logs type: array items: $ref: '#/components/schemas/GitLog' ignore: description: Git ignore files type: array items: type: string git: description: Git url type: string GitPayload: description: Git payload type: object properties: paths: description: Git paths type: array items: type: string commit_message: description: Commit message type: string branch: description: Branch type: string tag: description: Tag type: string DataSource: description: Data source model type: object allOf: - $ref: '#/components/schemas/ModelWithKey' - properties: name: description: Data source name type: string description: description: Data source description type: string type: description: Data source type type: string host: description: Data source host type: string port: description: Data source port type: string url: description: Data source url type: string hosts: description: Data source hosts type: array items: type: string database: description: Data source database type: string username: description: Data source username type: string password: description: Data source password type: string enabled: description: Data source enabled type: boolean connect_type: description: Data source connect type type: string status: description: Data source status type: string error: description: Data source error type: string extra: description: Data source extra type: object Schedule: description: Schedule model type: object allOf: - $ref: '#/components/schemas/ModelWithKey' - properties: spider_id: description: Schedule spider ID type: string cron: description: Schedule cron type: string example: "* * * * *" entry_id: description: Schedule entry ID type: string example: 1 cmd: description: Schedule execute command type: string example: scrapy crawl spider param: description: Schedule execute command param type: string example: -a param1=value1 -a param2=value2 mode: description: Schedule task mode type: string example: random node_ids: enabled: description: Schedule enabled type: boolean example: true user_id: description: Schedule user ID type: string User: description: User model type: object allOf: - $ref: '#/components/schemas/Model' - properties: username: description: User username type: string email: description: User email type: string role: description: User role type: string Token: description: Token model type: object allOf: - $ref: '#/components/schemas/Model' - properties: name: description: Token name type: string token: description: Token type: string Plugin: description: Plugin model type: object allOf: - $ref: '#/components/schemas/ModelWithNameDescription' - properties: short_name: description: Plugin short name type: string full_name: description: Plugin full name type: string proto: description: Plugin protocol type: string active: description: Plugin active type: boolean endpoint: description: Plugin endpoint type: string cmd: description: Plugin cmd type: string docker_cmd: description: Plugin docker cmd type: string docker_dir: description: Plugin docker directory type: string event_key: description: Plugin event key $ref: '#/components/schemas/PluginEventKey' install_type: description: Plugin install type type: string install_url: description: Plugin install url type: string install_cmd: description: Plugin install cmd type: string deploy_mode: description: Plugin deploy mode type: string auto_start: description: Plugin auto start type: boolean ui_components: description: Plugin ui components type: array items: $ref: '#/components/schemas/PluginUIComponent' ui_sidebar_navs: description: Plugin ui sidebar navs type: array items: $ref: '#/components/schemas/PluginUINav' ui_assets: description: Plugin ui assets type: array items: $ref: '#/components/schemas/PluginUIAsset' lang_url: description: Plugin language url type: string status: description: Plugin status $ref: '#/components/schemas/PluginStatus' PluginEventKey: description: Plugin event key model type: object properties: include: description: Plugin included event key type: array items: type: string exclude: description: Plugin excluded event key type: array items: type: string PluginUIComponent: description: Plugin ui component model type: object properties: name: description: Plugin ui component name type: string title: description: Plugin ui component title type: string src: description: Plugin ui component src type: string type: description: Plugin ui component type type: string path: description: Plugin ui component path type: string parent_paths: description: Plugin ui component parent paths type: array items: type: string PluginUINav: description: Plugin ui nav model type: object properties: path: description: Plugin ui nav path type: string title: description: Plugin ui nav title type: string icon: description: Plugin ui nav icon type: array items: type: string children: description: Plugin ui nav children type: array items: $ref: '#/components/schemas/PluginUINav' PluginUIAsset: description: Plugin ui asset model type: object properties: path: description: Plugin ui asset path type: string type: description: Plugin ui asset type type: string PluginStatus: description: Plugin status model type: object allOf: - $ref: '#/components/schemas/Model' - properties: plugin_id: description: Plugin ID type: string node_id: description: Node ID type: string status: description: Plugin status type: string pid: description: Plugin process ID type: integer error: description: Plugin error type: string node: description: Node model $ref: '#/components/schemas/Node' PublicPlugin: description: Public plugin model type: object properties: id: description: Public plugin ID type: string name: description: Public plugin name type: string full_name: description: Public plugin full name type: string description: description: Public plugin description type: string html_url: description: Public plugin html url type: string pushed_at: description: Public plugin pushed at type: string created_at: description: Public plugin created at type: string updated_at: description: Public plugin updated at type: string securitySchemes: apiToken: type: apiKey in: header name: Authorization description: API Token x-displayName: API Token ================================================ FILE: core/docs/package.json ================================================ { "name": "docs", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "publish": "node scripts/publish.js" }, "author": "", "license": "ISC", "devDependencies": { "chalk": "^4.1.2", "qiniu": "^7.4.0", "walk-sync": "^3.0.0" } } ================================================ FILE: core/docs/scripts/publish.js ================================================ const path = require('path') const qiniu = require('qiniu') const walkSync = require('walk-sync') const chalk = require('chalk') // target directory const targetDir = './api' // access key const accessKey = process.env.QINIU_ACCESS_KEY // secret key const secretKey = process.env.QINIU_SECRET_KEY // bucket const bucket = process.env.QINIU_BUCKET // config const config = new qiniu.conf.Config() // zone config.zone = qiniu.zone[process.env.QINIU_ZONE] function uploadFile(localFile, key) { // options const options = { scope: `${bucket}:${key}`, } // mac const mac = new qiniu.auth.digest.Mac(accessKey, secretKey) // put policy const putPolicy = new qiniu.rs.PutPolicy(options) // upload token const uploadToken = putPolicy.uploadToken(mac) return new Promise((resolve, reject) => { const formUploader = new qiniu.form_up.FormUploader(config) const putExtra = new qiniu.form_up.PutExtra() formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr, respBody, respInfo) { if (respErr) { throw respErr } if (respInfo.statusCode === 200) { console.log(`${chalk.green('uploaded')} ${localFile} => ${key}`) resolve() } else if (respInfo.statusCode === 614) { console.log(`${chalk.yellow('exists')} ${localFile} => ${key}`) resolve() } else { const errMsg = `${chalk.red('error[' + respInfo.statusCode + ']')} ${localFile} => ${key}` console.error(errMsg) reject(new Error(respBody)) } }) }) } async function main() { // paths const paths = walkSync(targetDir, { includeBasePath: true, directories: false, }) // iterate paths for (const filePath of paths) { const localFile = path.resolve(filePath) const key = filePath.replace(targetDir + '/', '') try { await uploadFile(localFile, key) } finally { // do nothing } } } (async () => { await main() })() ================================================ FILE: core/ds/cockroachdb.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" ) type CockroachdbService struct { SqlService } func NewDataSourceCockroachdbService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &CockroachdbService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, trace.TraceError(err) } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, trace.TraceError(err) } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultCockroachdbPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, trace.TraceError(err) } // session svc.s, err = utils.GetCockroachdbSession(svc.ds) if err != nil { return nil, trace.TraceError(err) } // collection svc.col = svc.s.Collection(svc.dc.Name) return svc, nil } ================================================ FILE: core/ds/default.go ================================================ package ds ================================================ FILE: core/ds/es.go ================================================ package ds import ( "context" "encoding/json" "errors" "fmt" "github.com/crawlab-team/crawlab/core/constants" constants2 "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" entity2 "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/trace" "github.com/elastic/go-elasticsearch/v8" "github.com/elastic/go-elasticsearch/v8/esapi" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson/primitive" "strings" "sync" "time" ) type ElasticsearchService struct { // dependencies modelSvc service.ModelService // internals dc *models.DataCollection // models.DataCollection ds *models.DataSource // models.DataSource c *elasticsearch.Client // elasticsearch.Client t time.Time } func (svc *ElasticsearchService) Insert(records ...interface{}) (err error) { // wait group var wg sync.WaitGroup wg.Add(len(records)) // iterate records for _, r := range records { // async operation go func(r interface{}) { switch r.(type) { case entity.Result: // convert type to entity.Result d := r.(entity.Result) // get document id id := d.GetValue("id") var docId string switch id.(type) { case string: docId = id.(string) } if docId == "" { docId = uuid.New().String() // generate new uuid if id is empty } // collection d[constants2.DataCollectionKey] = svc.dc.Name // index request req := esapi.IndexRequest{ Index: svc.getIndexName(), DocumentID: docId, Body: strings.NewReader(d.String()), } // perform request res, err := req.Do(context.Background(), svc.c) if err != nil { trace.PrintError(err) wg.Done() return } defer res.Body.Close() if res.IsError() { trace.PrintError(errors.New(fmt.Sprintf("[ElasticsearchService] [%s] error inserting record: %v", res.Status(), r))) } // release wg.Done() default: wg.Done() return } }(r) } // wait wg.Wait() return nil } func (svc *ElasticsearchService) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) { data, err := svc.getListResponse(query, opts, false) if err != nil { return nil, err } for _, hit := range data.Hits.Hits { results = append(results, hit.Source) } return results, nil } func (svc *ElasticsearchService) Count(query generic.ListQuery) (n int, err error) { data, err := svc.getListResponse(query, nil, true) if err != nil { return n, err } return int(data.Hits.Total.Value), nil } func (svc *ElasticsearchService) getListResponse(query generic.ListQuery, opts *generic.ListOptions, trackTotalHits bool) (data *entity2.ElasticsearchResponseData, err error) { if opts == nil { opts = &generic.ListOptions{} } query = append(query, generic.ListQueryCondition{ Key: constants2.DataCollectionKey, Op: constants2.FilterOpEqual, Value: svc.dc.Name, }) res, err := svc.c.Search( svc.c.Search.WithContext(context.Background()), svc.c.Search.WithIndex(svc.getIndexName()), svc.c.Search.WithBody(utils.GetElasticsearchQueryWithOptions(query, opts)), svc.c.Search.WithTrackTotalHits(trackTotalHits), ) if err != nil { return nil, trace.TraceError(err) } defer res.Body.Close() if res.IsError() { err = errors.New(fmt.Sprintf("[ElasticsearchService] [%s] error listing records: response=%s, query=%v opts=%v", res.Status(), res.String(), query, opts)) trace.PrintError(err) return nil, err } data = &entity2.ElasticsearchResponseData{} if err := json.NewDecoder(res.Body).Decode(data); err != nil { return nil, trace.TraceError(err) } return data, nil } func (svc *ElasticsearchService) getIndexName() (index string) { if svc.ds.Database == "" { return svc.dc.Name } else { return svc.ds.Name } } func NewDataSourceElasticsearchService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &ElasticsearchService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, err } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, err } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultElasticsearchPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, err } // client svc.c, err = utils.GetElasticsearchClient(svc.ds) if err != nil { return nil, err } return svc, nil } func (svc *ElasticsearchService) Index(fields []string) { // TODO: implement me } func (svc *ElasticsearchService) SetTime(t time.Time) { svc.t = t } func (svc *ElasticsearchService) GetTime() (t time.Time) { return svc.t } ================================================ FILE: core/ds/kafka.go ================================================ package ds import ( "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/trace" "github.com/segmentio/kafka-go" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type KafkaService struct { // dependencies modelSvc service.ModelService // internals dc *models.DataCollection // models.DataCollection ds *models.DataSource // models.DataSource c *kafka.Conn // kafka.Conn rb backoff.BackOff t time.Time } func (svc *KafkaService) Insert(records ...interface{}) (err error) { var messages []kafka.Message for _, r := range records { switch r.(type) { case entity.Result: d := r.(entity.Result) messages = append(messages, kafka.Message{ Topic: svc.ds.Database, Key: []byte(d.GetTaskId().Hex()), Value: d.Bytes(), }) } } _, err = svc.c.WriteMessages(messages...) if err != nil { return trace.TraceError(err) } return nil } func (svc *KafkaService) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) { // N/A return nil, nil } func (svc *KafkaService) Count(query generic.ListQuery) (n int, err error) { // N/A return 0, nil } func NewDataSourceKafkaService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &KafkaService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, err } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, err } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultKafkaPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, err } return svc, nil } func (svc *KafkaService) Index(fields []string) { // TODO: implement me } func (svc *KafkaService) SetTime(t time.Time) { svc.t = t } func (svc *KafkaService) GetTime() (t time.Time) { return svc.t } ================================================ FILE: core/ds/mongo.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "time" ) type MongoService struct { // dependencies modelSvc service.ModelService // internals dc *models.DataCollection // models.DataCollection ds *models.DataSource // models.DataSource c *mongo2.Client db *mongo2.Database col *mongo.Col t time.Time } func (svc *MongoService) Insert(records ...interface{}) (err error) { _, err = svc.col.InsertMany(records) return err } func (svc *MongoService) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) { var docs []models.Result if err := svc.col.Find(utils.GetMongoQuery(query), utils.GetMongoOpts(opts)).All(&docs); err != nil { return nil, err } for i := range docs { results = append(results, &docs[i]) } return results, nil } func (svc *MongoService) Count(query generic.ListQuery) (n int, err error) { return svc.col.Count(utils.GetMongoQuery(query)) } func NewDataSourceMongoService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &MongoService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, err } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, err } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultMongoPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, err } // mongo client svc.c, err = utils2.GetMongoClient(svc.ds) if err != nil { return nil, err } // mongo database svc.db = mongo.GetMongoDb(svc.ds.Database, mongo.WithDbClient(svc.c)) // mongo col svc.col = mongo.GetMongoColWithDb(svc.dc.Name, svc.db) return svc, nil } func (svc *MongoService) Index(fields []string) { // TODO: implement me } func (svc *MongoService) SetTime(t time.Time) { svc.t = t } func (svc *MongoService) GetTime() (t time.Time) { return svc.t } ================================================ FILE: core/ds/mssql.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" ) type MssqlService struct { SqlService } func NewDataSourceMssqlService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &MssqlService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, trace.TraceError(err) } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, trace.TraceError(err) } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultMssqlPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, trace.TraceError(err) } // session svc.s, err = utils2.GetMssqlSession(svc.ds) if err != nil { return nil, trace.TraceError(err) } // collection svc.col = svc.s.Collection(svc.dc.Name) return svc, nil } ================================================ FILE: core/ds/mssql_test.go ================================================ package ds import "testing" func TestNewDataSourceMssqlService(t *testing.T) { t.Run("insert", func(t *testing.T) { }) } ================================================ FILE: core/ds/mysql.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" utils2 "github.com/crawlab-team/crawlab/core/utils" "go.mongodb.org/mongo-driver/bson/primitive" ) type MysqlService struct { SqlService } func NewDataSourceMysqlService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &MysqlService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, err } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, err } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultMysqlPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, err } // session svc.s, err = utils2.GetMysqlSession(svc.ds) if err != nil { return nil, err } // collection svc.col = svc.s.Collection(svc.dc.Name) return svc, nil } ================================================ FILE: core/ds/options.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type DataSourceServiceOption func(svc interfaces.DataSourceService) func WithMonitorInterval(duration time.Duration) DataSourceServiceOption { return func(svc interfaces.DataSourceService) { svc.SetMonitorInterval(duration) } } ================================================ FILE: core/ds/postgresql.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" ) type PostgresqlService struct { SqlService } func NewDataSourcePostgresqlService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &PostgresqlService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, trace.TraceError(err) } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, trace.TraceError(err) } } // data source defaults if svc.ds.Host == "" { svc.ds.Host = constants.DefaultHost } if svc.ds.Port == 0 { svc.ds.Port = constants.DefaultPostgresqlPort } // data source password pwd, err := svc.modelSvc.GetPasswordById(svc.ds.Id) if err == nil { svc.ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return nil, err } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, trace.TraceError(err) } // session svc.s, err = utils2.GetPostgresqlSession(svc.ds) if err != nil { return nil, trace.TraceError(err) } // collection svc.col = svc.s.Collection(svc.dc.Name) return svc, nil } ================================================ FILE: core/ds/service.go ================================================ package ds import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" constants2 "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/result" "github.com/crawlab-team/crawlab/core/utils" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "sync" "time" ) type Service struct { // dependencies modelSvc service.ModelService // internals timeout time.Duration monitorInterval time.Duration stopped bool } func (svc *Service) Init() { // result service registry reg := result.GetResultServiceRegistry() // register result services reg.Register(constants.DataSourceTypeMongo, NewDataSourceMongoService) reg.Register(constants.DataSourceTypeMysql, NewDataSourceMysqlService) reg.Register(constants.DataSourceTypePostgresql, NewDataSourcePostgresqlService) reg.Register(constants.DataSourceTypeMssql, NewDataSourceMssqlService) reg.Register(constants.DataSourceTypeSqlite, NewDataSourceSqliteService) reg.Register(constants.DataSourceTypeCockroachdb, NewDataSourceCockroachdbService) reg.Register(constants.DataSourceTypeElasticSearch, NewDataSourceElasticsearchService) reg.Register(constants.DataSourceTypeKafka, NewDataSourceKafkaService) } func (svc *Service) Start() { // start monitoring go svc.Monitor() } func (svc *Service) Wait() { utils.DefaultWait() } func (svc *Service) Stop() { svc.stopped = true } func (svc *Service) ChangePassword(id primitive.ObjectID, password string) (err error) { p, err := svc.modelSvc.GetPasswordById(id) if err == nil { // exists, save encryptedPassword, err := utils.EncryptAES(password) if err != nil { return err } p.Password = encryptedPassword if err := delegate.NewModelDelegate(p).Save(); err != nil { return err } return nil } else if err.Error() == mongo.ErrNoDocuments.Error() { // not exists, add encryptedPassword, err := utils.EncryptAES(password) if err != nil { return err } p = &models.Password{ Id: id, Password: encryptedPassword, } if err := delegate.NewModelDelegate(p).Add(); err != nil { return err } return nil } else { // error return err } } func (svc *Service) Monitor() { for { // return if stopped if svc.stopped { return } // monitor if err := svc.monitor(); err != nil { trace.PrintError(err) } // wait time.Sleep(svc.monitorInterval) } } func (svc *Service) CheckStatus(id primitive.ObjectID) (err error) { ds, err := svc.modelSvc.GetDataSourceById(id) if err != nil { return err } return svc.checkStatus(ds, true) } func (svc *Service) SetTimeout(duration time.Duration) { svc.timeout = duration } func (svc *Service) SetMonitorInterval(duration time.Duration) { svc.monitorInterval = duration } func (svc *Service) monitor() (err error) { // start tic := time.Now() log.Debugf("[DataSourceService] start monitoring") // data source list dsList, err := svc.modelSvc.GetDataSourceList(nil, nil) if err != nil { return err } // waiting group wg := sync.WaitGroup{} wg.Add(len(dsList)) // iterate data source list for _, ds := range dsList { // async operation go func(ds models.DataSource) { // check status and save _ = svc.checkStatus(&ds, true) // release wg.Done() }(ds) } // wait wg.Wait() // finish toc := time.Now() log.Debugf("[DataSourceService] finished monitoring. elapsed: %d ms", (toc.Sub(tic)).Milliseconds()) return nil } func (svc *Service) checkStatus(ds *models.DataSource, save bool) (err error) { // password if ds.Password == "" { pwd, err := svc.modelSvc.GetPasswordById(ds.Id) if err == nil { ds.Password, err = utils.DecryptAES(pwd.Password) if err != nil { return err } } else if err.Error() != mongo.ErrNoDocuments.Error() { return trace.TraceError(err) } } // check status if err := svc._checkStatus(ds); err != nil { ds.Status = constants2.DataSourceStatusOffline ds.Error = err.Error() } else { ds.Status = constants2.DataSourceStatusOnline ds.Error = "" } // save if save { return svc._save(ds) } return nil } func (svc *Service) _save(ds *models.DataSource) (err error) { log.Debugf("[DataSourceService] saving data source: name=%s, type=%s, status=%s, error=%s", ds.Name, ds.Type, ds.Status, ds.Error) return delegate.NewModelDelegate(ds).Save() } func (svc *Service) _checkStatus(ds *models.DataSource) (err error) { switch ds.Type { case constants.DataSourceTypeMongo: _, err := utils2.GetMongoClientWithTimeout(ds, svc.timeout) if err != nil { return err } case constants.DataSourceTypeMysql: s, err := utils2.GetMysqlSessionWithTimeout(ds, svc.timeout) if err != nil { return err } if s != nil { s.Close() } case constants.DataSourceTypePostgresql: s, err := utils2.GetPostgresqlSessionWithTimeout(ds, svc.timeout) if err != nil { return err } if s != nil { s.Close() } case constants.DataSourceTypeMssql: s, err := utils2.GetMssqlSessionWithTimeout(ds, svc.timeout) if err != nil { return err } if s != nil { s.Close() } case constants.DataSourceTypeSqlite: s, err := utils2.GetSqliteSessionWithTimeout(ds, svc.timeout) if err != nil { return err } if s != nil { s.Close() } case constants.DataSourceTypeCockroachdb: s, err := utils2.GetCockroachdbSessionWithTimeout(ds, svc.timeout) if err != nil { return err } if s != nil { s.Close() } case constants.DataSourceTypeElasticSearch: _, err := utils2.GetElasticsearchClientWithTimeout(ds, svc.timeout) if err != nil { return err } case constants.DataSourceTypeKafka: c, err := utils2.GetKafkaConnectionWithTimeout(ds, svc.timeout) if err != nil { return err } if c != nil { c.Close() } default: log.Warnf("[DataSourceService] invalid data source type: %s", ds.Type) } return nil } func NewDataSourceService(opts ...DataSourceServiceOption) (svc2 interfaces.DataSourceService, err error) { // service svc := &Service{ monitorInterval: 15 * time.Second, timeout: 10 * time.Second, } // apply options for _, opt := range opts { opt(svc) } // dependency injection if err := container.GetContainer().Invoke(func(modelSvc service.ModelService) { svc.modelSvc = modelSvc }); err != nil { return nil, trace.TraceError(err) } // initialize svc.Init() // start svc.Start() return svc, nil } var _dsSvc interfaces.DataSourceService func GetDataSourceService() (svc interfaces.DataSourceService, err error) { if _dsSvc != nil { return _dsSvc, nil } svc, err = NewDataSourceService() if err != nil { return nil, err } _dsSvc = svc return svc, nil } ================================================ FILE: core/ds/sql.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/trace" "github.com/upper/db/v4" "time" ) type SqlService struct { // dependencies modelSvc service.ModelService // internals ds *models.DataSource dc *models.DataCollection s db.Session col db.Collection t time.Time } func (svc *SqlService) Insert(records ...interface{}) (err error) { for _, d := range records { var r entity.Result switch d.(type) { case entity.Result: r = d.(entity.Result) default: continue } _r := r.Flatten() if _, err = svc.col.Insert(_r); err != nil { trace.PrintError(err) continue } } return nil } func (svc *SqlService) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) { var docs []entity.Result if err := svc.col.Find(utils2.GetSqlQuery(query)). Offset(opts.Skip). Limit(opts.Limit).All(&docs); err != nil { return nil, trace.TraceError(err) } for i := range docs { d := docs[i].ToJSON() results = append(results, &d) } return results, nil } func (svc *SqlService) Count(query generic.ListQuery) (n int, err error) { nInt64, err := svc.col.Find(utils2.GetSqlQuery(query)).Count() if err != nil { return n, err } return int(nInt64), nil } func (svc *SqlService) Index(fields []string) { // TODO: implement me } func (svc *SqlService) SetTime(t time.Time) { svc.t = t } func (svc *SqlService) GetTime() (t time.Time) { return svc.t } ================================================ FILE: core/ds/sql_options.go ================================================ package ds type SqlOptions struct { DefaultHost string DefaultPort string } ================================================ FILE: core/ds/sqlite.go ================================================ package ds import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" utils2 "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" ) type SqliteService struct { SqlService } func NewDataSourceSqliteService(colId primitive.ObjectID, dsId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &SqliteService{} // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, trace.TraceError(err) } // data source if dsId.IsZero() { svc.ds = &models.DataSource{} } else { svc.ds, err = svc.modelSvc.GetDataSourceById(dsId) if err != nil { return nil, trace.TraceError(err) } } // data collection svc.dc, err = svc.modelSvc.GetDataCollectionById(colId) if err != nil { return nil, trace.TraceError(err) } // session svc.s, err = utils2.GetSqliteSession(svc.ds) if err != nil { return nil, trace.TraceError(err) } // collection svc.col = svc.s.Collection(svc.dc.Name) return svc, nil } ================================================ FILE: core/entity/address.go ================================================ package entity import ( "errors" "fmt" "strings" ) type Address struct { Host string Port string } func (a *Address) String() (res string) { return fmt.Sprintf("%s:%s", a.Host, a.Port) } func (a *Address) IsEmpty() (res bool) { return a.Host == "" || a.Port == "" } func (a *Address) Value() (res interface{}) { return a } type AddressOptions struct { Host string Port string } func NewAddress(opts *AddressOptions) (res *Address) { if opts == nil { opts = &AddressOptions{} } //if opts.Host == "" { // opts.Host = "localhost" //} if opts.Port == "" { opts.Port = "9666" } return &Address{ Host: opts.Host, Port: opts.Port, } } func NewAddressFromString(address string) (res *Address, err error) { parts := strings.Split(address, ":") if len(parts) == 1 { return NewAddress(&AddressOptions{Host: parts[0]}), nil } else if len(parts) == 2 { return NewAddress(&AddressOptions{Host: parts[0], Port: parts[1]}), nil } else { return nil, errors.New(fmt.Sprintf("parsing address error: %v", err)) } } ================================================ FILE: core/entity/color.go ================================================ package entity type Color struct { Name string `json:"name"` Hex string `json:"hex"` } func (c *Color) GetHex() string { return c.Hex } func (c *Color) GetName() string { return c.Name } func (c *Color) Value() interface{} { return c } ================================================ FILE: core/entity/common.go ================================================ 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 } ================================================ FILE: core/entity/config_spider.go ================================================ 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"` } ================================================ FILE: core/entity/data_field.go ================================================ package entity type DataField struct { Key string `json:"key" bson:"key"` Type string `json:"type" bson:"type"` } ================================================ FILE: core/entity/dependency.go ================================================ package entity import "go.mongodb.org/mongo-driver/bson/primitive" type DependencyResult struct { Name string `json:"name,omitempty" bson:"name,omitempty"` NodeIds []primitive.ObjectID `json:"node_ids,omitempty" bson:"node_ids,omitempty"` Versions []string `json:"versions,omitempty" bson:"versions,omitempty"` LatestVersion string `json:"latest_version" bson:"latest_version"` Count int `json:"count,omitempty" bson:"count,omitempty"` Upgradable bool `json:"upgradable" bson:"upgradable"` Downgradable bool `json:"downgradable" bson:"downgradable"` Installable bool `json:"installable" bson:"installable"` } ================================================ FILE: core/entity/doc.go ================================================ package entity type DocItem struct { Title string `json:"title"` Url string `json:"url"` Path string `json:"path"` Children []DocItem `json:"children"` } ================================================ FILE: core/entity/es.go ================================================ package entity /* ElasticsearchResponseData JSON format { "took" : 6, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 60, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "test_table", "_id" : "c39ad9a2-9a37-49fb-b7ea-f1b55913e0af", "_score" : 1.0, "_source" : { "_tid" : "62524ac7f5f99e7ef594de64", "author" : "James Baldwin", "tags" : [ "love" ], "text" : "“Love does not begin and end the way we seem to think it does. Love is a battle, love is a war; love is a growing up.”" } } ] } } */ type ElasticsearchResponseData struct { Took int64 `json:"took"` Timeout bool `json:"timeout"` Hits struct { Total struct { Value int64 `json:"value"` Relation string `json:"relation"` } `json:"total"` MaxScore float64 `json:"max_score"` Hits []struct { Index string `json:"_index"` Id string `json:"_id"` Score float64 `json:"_score"` Source interface{} `json:"_source"` } `json:"hits"` } `json:"hits"` } ================================================ FILE: core/entity/event.go ================================================ package entity type EventData struct { Event string Data interface{} } func (d *EventData) GetEvent() string { return d.Event } func (d *EventData) GetData() interface{} { return d.Data } ================================================ FILE: core/entity/export.go ================================================ package entity import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Export struct { Id string `json:"id"` Type string `json:"type"` Target string `json:"target"` Filter interfaces.Filter `json:"filter"` Status string `json:"status"` StartTs time.Time `json:"start_ts"` EndTs time.Time `json:"end_ts"` FileName string `json:"file_name"` DownloadPath string `json:"-"` Limit int `json:"-"` } func (e *Export) GetId() string { return e.Id } func (e *Export) GetType() string { return e.Type } func (e *Export) GetTarget() string { return e.Target } func (e *Export) GetFilter() interfaces.Filter { return e.Filter } func (e *Export) GetStatus() string { return e.Status } func (e *Export) GetStartTs() time.Time { return e.StartTs } func (e *Export) GetEndTs() time.Time { return e.EndTs } func (e *Export) GetDownloadPath() string { return e.DownloadPath } ================================================ FILE: core/entity/filter.go ================================================ package entity import ( "github.com/crawlab-team/crawlab/core/interfaces" "reflect" ) type Condition struct { Key string `json:"key"` Op string `json:"op"` Value interface{} `json:"value"` } func (c *Condition) GetKey() (key string) { return c.Key } func (c *Condition) SetKey(key string) { c.Key = key } func (c *Condition) GetOp() (op string) { return c.Op } func (c *Condition) SetOp(op string) { c.Op = op } func (c *Condition) GetValue() (value interface{}) { return c.Value } func (c *Condition) SetValue(value interface{}) { c.Value = value } type Filter struct { IsOr bool `form:"is_or" url:"is_or"` Conditions []*Condition `json:"conditions"` } func (f *Filter) GetIsOr() (isOr bool) { return f.IsOr } func (f *Filter) SetIsOr(isOr bool) { f.IsOr = isOr } func (f *Filter) GetConditions() (conditions []interfaces.FilterCondition) { for _, c := range f.Conditions { conditions = append(conditions, c) } return conditions } func (f *Filter) SetConditions(conditions []interfaces.FilterCondition) { f.Conditions = make([]*Condition, len(conditions)) for _, c := range conditions { f.Conditions = append(f.Conditions, c.(*Condition)) } } func (f *Filter) IsNil() (ok bool) { val := reflect.ValueOf(f) return val.IsNil() } ================================================ FILE: core/entity/filter_select_option.go ================================================ package entity type FilterSelectOption struct { Value interface{} `json:"value" bson:"value"` Label string `json:"label" bson:"label"` } ================================================ FILE: core/entity/fs_file_info.go ================================================ package entity import ( "github.com/crawlab-team/crawlab/core/interfaces" "os" "time" ) type FsFileInfo struct { Name string `json:"name"` // file name Path string `json:"path"` // file path FullPath string `json:"full_path"` // file full path Extension string `json:"extension"` // file extension IsDir bool `json:"is_dir"` // whether it is directory FileSize int64 `json:"file_size"` // file size (bytes) Children []interfaces.FsFileInfo `json:"children"` // children for sub-directory ModTime time.Time `json:"mod_time"` // modification time Mode os.FileMode `json:"mode"` // file mode Hash string `json:"hash"` // file hash } func (f *FsFileInfo) GetName() string { return f.Name } func (f *FsFileInfo) GetPath() string { return f.Path } func (f *FsFileInfo) GetFullPath() string { return f.FullPath } func (f *FsFileInfo) GetExtension() string { return f.Extension } func (f *FsFileInfo) GetIsDir() bool { return f.IsDir } func (f *FsFileInfo) GetFileSize() int64 { return f.FileSize } func (f *FsFileInfo) GetModTime() time.Time { return f.ModTime } func (f *FsFileInfo) GetMode() os.FileMode { return f.Mode } func (f *FsFileInfo) GetHash() string { return f.Hash } func (f *FsFileInfo) GetChildren() []interfaces.FsFileInfo { return f.Children } ================================================ FILE: core/entity/git.go ================================================ package entity type GitPayload struct { Paths []string `json:"paths"` CommitMessage string `json:"commit_message"` Branch string `json:"branch"` Tag string `json:"tag"` } type GitConfig struct { Url string `json:"url" bson:"url"` } ================================================ FILE: core/entity/grpc_base_service_message.go ================================================ package entity import ( "encoding/json" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/trace" ) type GrpcBaseServiceMessage struct { ModelId interfaces.ModelId `json:"id"` Data []byte `json:"d"` } func (msg *GrpcBaseServiceMessage) GetModelId() interfaces.ModelId { return msg.ModelId } func (msg *GrpcBaseServiceMessage) GetData() []byte { return msg.Data } func (msg *GrpcBaseServiceMessage) ToBytes() (data []byte) { data, err := json.Marshal(*msg) if err != nil { _ = trace.TraceError(err) return data } return data } ================================================ FILE: core/entity/grpc_base_service_params.go ================================================ package entity import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcBaseServiceParams struct { Query bson.M `json:"q"` Id primitive.ObjectID `json:"id"` Update bson.M `json:"u"` Doc interfaces.Model `json:"d"` Fields []string `json:"f"` FindOptions *mongo.FindOptions `json:"o"` Docs []interface{} `json:"dl"` User interfaces.User `json:"U"` } func (params *GrpcBaseServiceParams) Value() interface{} { return params } ================================================ FILE: core/entity/grpc_delegate_message.go ================================================ package entity import ( "encoding/json" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/trace" ) type GrpcDelegateMessage struct { ModelId interfaces.ModelId `json:"id"` Method interfaces.ModelDelegateMethod `json:"m"` Data []byte `json:"d"` } func (msg *GrpcDelegateMessage) GetModelId() interfaces.ModelId { return msg.ModelId } func (msg *GrpcDelegateMessage) GetMethod() interfaces.ModelDelegateMethod { return msg.Method } func (msg *GrpcDelegateMessage) GetData() []byte { return msg.Data } func (msg *GrpcDelegateMessage) ToBytes() (data []byte) { data, err := json.Marshal(*msg) if err != nil { _ = trace.TraceError(err) return data } return data } ================================================ FILE: core/entity/grpc_event_service_message.go ================================================ package entity type GrpcEventServiceMessage struct { Type string `json:"type"` Events []string `json:"events"` Key string `json:"key"` Data []byte `json:"data"` } ================================================ FILE: core/entity/grpc_subscribe.go ================================================ package entity import ( "github.com/crawlab-team/crawlab/core/interfaces" ) type GrpcSubscribe struct { Stream interfaces.GrpcStream Finished chan bool } func (sub *GrpcSubscribe) GetStream() interfaces.GrpcStream { return sub.Stream } func (sub *GrpcSubscribe) GetStreamBidirectional() interfaces.GrpcStreamBidirectional { stream, ok := sub.Stream.(interfaces.GrpcStreamBidirectional) if !ok { return nil } return stream } func (sub *GrpcSubscribe) GetFinished() chan bool { return sub.Finished } ================================================ FILE: core/entity/http.go ================================================ package entity import "go.mongodb.org/mongo-driver/bson/primitive" 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"` } type BatchRequestPayload struct { Ids []primitive.ObjectID `form:"ids" json:"ids"` } type BatchRequestPayloadWithStringData struct { Ids []primitive.ObjectID `form:"ids" json:"ids"` Data string `form:"data" json:"data"` Fields []string `form:"fields" json:"fields"` } type FileRequestPayload struct { Path string `json:"path" form:"path"` NewPath string `json:"new_path" form:"new_path"` Data string `json:"data" form:"data"` } ================================================ FILE: core/entity/model_delegate.go ================================================ package entity import "github.com/crawlab-team/crawlab/core/interfaces" type ModelDelegate struct { Id interfaces.ModelId `json:"id"` ColName string `json:"col_name"` Doc interfaces.Model `json:"doc"` Artifact interfaces.ModelArtifact `json:"a"` User interfaces.User `json:"u"` } ================================================ FILE: core/entity/model_info.go ================================================ package entity import "github.com/crawlab-team/crawlab/core/interfaces" type ModelInfo struct { Id interfaces.ModelId ColName string } ================================================ FILE: core/entity/node.go ================================================ package entity type NodeInfo struct { Key string `json:"key"` IsMaster bool `json:"is_master"` Name string `json:"name"` Ip string `json:"ip"` Mac string `json:"mac"` Hostname string `json:"hostname"` Description string `json:"description"` AuthKey string `json:"auth_key"` MaxRunners int `json:"max_runners"` } func (n NodeInfo) Value() interface{} { return n } ================================================ FILE: core/entity/notification_variable.go ================================================ package entity import "fmt" type NotificationVariable struct { Category string `json:"category"` Name string `json:"name"` } func (v *NotificationVariable) GetKey() string { return fmt.Sprintf("${%s:%s}", v.Category, v.Name) } ================================================ FILE: core/entity/pagination.go ================================================ package entity import "github.com/crawlab-team/crawlab/core/constants" type Pagination struct { Page int `form:"page" url:"page"` Size int `form:"size" url:"size"` } func (p *Pagination) IsZero() (ok bool) { return p.Page == 0 && p.Size == 0 } func (p *Pagination) IsDefault() (ok bool) { return p.Page == constants.PaginationDefaultPage && p.Size == constants.PaginationDefaultSize } ================================================ FILE: core/entity/result.go ================================================ package entity import ( "encoding/json" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" ) type Result map[string]interface{} func (r Result) Value() map[string]interface{} { return r } func (r Result) SetValue(key string, value interface{}) { r[key] = value } func (r Result) GetValue(key string) (value interface{}) { value, _ = r[key] return value } func (r Result) GetTaskId() (id primitive.ObjectID) { _tid, ok := r[constants.TaskKey] if !ok { return id } switch _tid.(type) { case string: oid, err := primitive.ObjectIDFromHex(_tid.(string)) if err != nil { return id } return oid default: return id } } func (r Result) SetTaskId(id primitive.ObjectID) { r[constants.TaskKey] = id } func (r Result) DenormalizeObjectId() (res Result) { for k, v := range r { switch v.(type) { case primitive.ObjectID: r[k] = v.(primitive.ObjectID).Hex() case Result: r[k] = v.(Result).DenormalizeObjectId() } } return r } func (r Result) ToJSON() (res Result) { r = r.DenormalizeObjectId() for k, v := range r { switch v.(type) { case []byte: r[k] = string(v.([]byte)) } } return r } func (r Result) Flatten() (res Result) { r = r.ToJSON() for k, v := range r { switch v.(type) { case string, bool, uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64: default: bytes, err := json.Marshal(v) if err != nil { trace.PrintError(err) return nil } r[k] = string(bytes) } } return r } func (r Result) String() (s string) { return string(r.Bytes()) } func (r Result) Bytes() (bytes []byte) { bytes, err := json.Marshal(r.ToJSON()) if err != nil { return bytes } return bytes } ================================================ FILE: core/entity/rpc.go ================================================ 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"` // 错误 } ================================================ FILE: core/entity/sort.go ================================================ package entity type Sort struct { Key string `json:"key"` Direction string `json:"d"` } ================================================ FILE: core/entity/spider.go ================================================ 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"` } ================================================ FILE: core/entity/stats.go ================================================ package entity type StatsDailyItem struct { Date string `json:"date" bson:"_id"` Tasks int64 `json:"tasks" bson:"tasks"` Results int64 `json:"results" bson:"results"` } type StatsTasksByStatusItem struct { Status string `json:"status" bson:"_id"` Tasks int64 `json:"tasks" bson:"tasks"` } ================================================ FILE: core/entity/system_info.go ================================================ package entity type SystemInfo struct { Edition string `json:"edition"` // edition. e.g. community / pro Version string `json:"version"` // version. e.g. v0.6.0 } ================================================ FILE: core/entity/task.go ================================================ package entity import ( "encoding/json" "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskMessage struct { Id primitive.ObjectID `json:"id"` Key string `json:"key"` Cmd string `json:"cmd"` Param string `json:"param"` } func (m *TaskMessage) ToString() (string, error) { data, err := json.Marshal(&m) if err != nil { return "", err } return string(data), err } type TaskRunOptions struct { } type StreamMessageTaskData struct { TaskId primitive.ObjectID `json:"task_id"` Records []Result `json:"data"` Logs []string `json:"logs"` } ================================================ FILE: core/entity/translation.go ================================================ package entity type Translation struct { Lang string `json:"lang"` Key string `json:"key"` Value string `json:"value"` } func (t Translation) GetLang() (l string) { return t.Lang } ================================================ FILE: core/entity/ttl_map.go ================================================ package entity import ( "sync" "time" ) type TTLMap struct { TTL time.Duration data sync.Map } type expireEntry struct { ExpiresAt time.Time Value interface{} } func (t *TTLMap) Store(key string, val interface{}) { t.data.Store(key, expireEntry{ ExpiresAt: time.Now().Add(t.TTL), Value: val, }) } func (t *TTLMap) Load(key string) (val interface{}) { entry, ok := t.data.Load(key) if !ok { return nil } expireEntry := entry.(expireEntry) if expireEntry.ExpiresAt.After(time.Now()) { return nil } return expireEntry.Value } func NewTTLMap(ttl time.Duration) (m *TTLMap) { m = &TTLMap{ TTL: ttl, } go func() { for now := range time.Tick(time.Second) { m.data.Range(func(k, v interface{}) bool { expiresAt := v.(expireEntry).ExpiresAt if expiresAt.Before(now) { m.data.Delete(k) } return true }) } }() return } ================================================ FILE: core/entity/version.go ================================================ 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] } ================================================ FILE: core/errors/base.go ================================================ package errors import ( "errors" "fmt" ) const ( ErrorPrefixController = "controller" ErrorPrefixModel = "model" ErrorPrefixFilter = "filter" ErrorPrefixHttp = "http" ErrorPrefixGrpc = "grpc" ErrorPrefixNode = "node" ErrorPrefixInject = "inject" ErrorPrefixSpider = "spider" ErrorPrefixFs = "fs" ErrorPrefixTask = "task" ErrorPrefixSchedule = "schedule" ErrorPrefixUser = "user" ErrorPrefixStats = "stats" ErrorPrefixEvent = "event" ErrorPrefixProcess = "process" ErrorPrefixGit = "git" ErrorPrefixResult = "result" ErrorPrefixDataSource = "data_source" ) type ErrorPrefix string func NewError(prefix ErrorPrefix, msg string) (err error) { return errors.New(fmt.Sprintf("%s error: %s", prefix, msg)) } ================================================ FILE: core/errors/controller.go ================================================ package errors func NewControllerError(msg string) (err error) { return NewError(ErrorPrefixController, msg) } var ErrorControllerInvalidControllerId = NewControllerError("invalid controller id") var ErrorControllerInvalidType = NewControllerError("invalid type") var ErrorControllerAddError = NewControllerError("add error") var ErrorControllerUpdateError = NewControllerError("update error") var ErrorControllerDeleteError = NewControllerError("delete error") var ErrorControllerNotImplemented = NewControllerError("not implemented") var ErrorControllerNoModelService = NewControllerError("no model service") var ErrorControllerRequestPayloadInvalid = NewControllerError("request payload invalid") var ErrorControllerMissingInCache = NewControllerError("missing in cache") var ErrorControllerNotCancellable = NewControllerError("not cancellable") var ErrorControllerMissingRequestFields = NewControllerError("missing request fields") var ErrorControllerEmptyResponse = NewControllerError("empty response") var ErrorControllerFilerNotFound = NewControllerError("filer not found") ================================================ FILE: core/errors/ds.go ================================================ package errors func NewDataSourceError(msg string) (err error) { return NewError(ErrorPrefixDataSource, msg) } var ( ErrorDataSourceInvalidType = NewDataSourceError("invalid type") ErrorDataSourceNotExists = NewDataSourceError("not exists") ErrorDataSourceNotExistsInContext = NewDataSourceError("not exists in context") ErrorDataSourceAlreadyExists = NewDataSourceError("already exists") ErrorDataSourceMismatch = NewDataSourceError("mismatch") ErrorDataSourceMissingRequiredFields = NewDataSourceError("missing required fields") ErrorDataSourceUnauthorized = NewDataSourceError("unauthorized") ) ================================================ FILE: core/errors/event.go ================================================ package errors func NewEventError(msg string) (err error) { return NewError(ErrorPrefixEvent, msg) } var ErrorEventNotFound = NewEventError("not found") var ErrorEventInvalidType = NewEventError("invalid type") var ErrorEventAlreadyExists = NewEventError("already exists") var ErrorEventUnknownAction = NewEventError("unknown action") ================================================ FILE: core/errors/filter.go ================================================ package errors func NewFilterError(msg string) (err error) { return NewError(ErrorPrefixFilter, msg) } var ErrorFilterInvalidOperation = NewFilterError("invalid operation") var ErrorFilterUnableToParseQuery = NewFilterError("unable to parse query") ================================================ FILE: core/errors/fs.go ================================================ package errors func NewFsError(msg string) (err error) { return NewError(ErrorPrefixFs, msg) } var ErrorFsForbidden = NewFsError("forbidden") var ErrorFsEmptyWorkspacePath = NewFsError("empty workspace path") var ErrorFsInvalidType = NewFsError("invalid type") var ErrorFsAlreadyExists = NewFsError("already exists") var ErrorFsInvalidContent = NewFsError("invalid content") ================================================ FILE: core/errors/git.go ================================================ package errors func NewGitError(msg string) (err error) { return NewError(ErrorPrefixGit, msg) } var ( ErrorGitInvalidAuthType = NewGitError("invalid auth type") ErrorGitNoMainBranch = NewGitError("no main branch") ) ================================================ FILE: core/errors/grpc.go ================================================ package errors func NewGrpcError(msg string) (err error) { return NewError(ErrorPrefixGrpc, msg) } var ( ErrorGrpcClientFailedToStart = NewGrpcError("client failed to start") ErrorGrpcServerFailedToListen = NewGrpcError("server failed to listen") ErrorGrpcServerFailedToServe = NewGrpcError("server failed to serve") ErrorGrpcClientNotExists = NewGrpcError("client not exists") ErrorGrpcClientAlreadyExists = NewGrpcError("client already exists") ErrorGrpcInvalidType = NewGrpcError("invalid type") ErrorGrpcNotAllowed = NewGrpcError("not allowed") ErrorGrpcSubscribeNotExists = NewGrpcError("subscribe not exists") ErrorGrpcStreamNotFound = NewGrpcError("stream not found") ErrorGrpcInvalidCode = NewGrpcError("invalid code") ErrorGrpcUnauthorized = NewGrpcError("unauthorized") ErrorGrpcInvalidNodeKey = NewGrpcError("invalid node key") ) ================================================ FILE: core/errors/http.go ================================================ package errors func NewHttpError(msg string) (err error) { return NewError(ErrorPrefixHttp, msg) } var ErrorHttpBadRequest = NewHttpError("bad request") var ErrorHttpUnauthorized = NewHttpError("unauthorized") var ErrorHttpNotFound = NewHttpError("not found") ================================================ FILE: core/errors/model.go ================================================ package errors import "errors" func NewModelError(msg string) (err error) { return NewError(ErrorPrefixModel, msg) } var ErrorModelInvalidType = NewModelError("invalid type") var ErrorModelInvalidModelId = NewModelError("invalid model id") var ErrorModelNotImplemented = NewModelError("not implemented") var ErrorModelNotFound = NewModelError("not found") var ErrorModelAlreadyExists = NewModelError("already exists") var ErrorModelNotExists = NewModelError("not exists") var ErrorModelMissingRequiredData = NewModelError("missing required data") var ErrorModelMissingId = errors.New("missing _id") var ErrorModelNotAllowed = NewModelError("not allowed") var ErrorModelDeleteListError = NewModelError("delete list error") var ErrorModelNilPointer = NewModelError("nil pointer") ================================================ FILE: core/errors/node.go ================================================ package errors func NewNodeError(msg string) (err error) { return NewError(ErrorPrefixNode, msg) } var ErrorNodeUnregistered = NewNodeError("unregistered") var ErrorNodeServiceNotExists = NewNodeError("service not exists") var ErrorNodeInvalidType = NewNodeError("invalid type") var ErrorNodeInvalidStatus = NewNodeError("invalid status") var ErrorNodeInvalidCode = NewNodeError("invalid code") var ErrorNodeInvalidNodeKey = NewNodeError("invalid node key") var ErrorNodeMonitorError = NewNodeError("monitor error") var ErrorNodeNotExists = NewNodeError("not exists") ================================================ FILE: core/errors/process.go ================================================ package errors func NewProcessError(msg string) (err error) { return NewError(ErrorPrefixProcess, msg) } var ( ErrorProcessReachedMaxErrors = NewProcessError("reached max errors") ErrorProcessDaemonProcessExited = NewProcessError("daemon process exited") ) ================================================ FILE: core/errors/result.go ================================================ package errors func NewResultError(msg string) (err error) { return NewError(ErrorPrefixResult, msg) } ================================================ FILE: core/errors/schedule.go ================================================ package errors func NewScheduleError(msg string) (err error) { return NewError(ErrorPrefixSchedule, msg) } //var ErrorSchedule = NewScheduleError("unregistered") ================================================ FILE: core/errors/spider.go ================================================ package errors func NewSpiderError(msg string) (err error) { return NewError(ErrorPrefixSpider, msg) } var ( ErrorSpiderMissingRequiredOption = NewSpiderError("missing required option") ErrorSpiderForbidden = NewSpiderError("forbidden") ) ================================================ FILE: core/errors/stats.go ================================================ package errors func NewStatsError(msg string) (err error) { return NewError(ErrorPrefixStats, msg) } var ErrorStatsInvalidType = NewStatsError("invalid type") ================================================ FILE: core/errors/store.go ================================================ package errors func NewInjectError(msg string) (err error) { return NewError(ErrorPrefixInject, msg) } var ErrorInjectEmptyValue = NewInjectError("empty value") var ErrorInjectNotExists = NewInjectError("not exists") var ErrorInjectInvalidType = NewInjectError("invalid type") ================================================ FILE: core/errors/task.go ================================================ package errors func NewTaskError(msg string) (err error) { return NewError(ErrorPrefixTask, msg) } var ( ErrorTaskNotExists = NewTaskError("not exists") ErrorTaskAlreadyExists = NewTaskError("already exists") ErrorTaskInvalidType = NewTaskError("invalid type") ErrorTaskProcessStillExists = NewTaskError("process still exists") ErrorTaskUnableToCancel = NewTaskError("unable to cancel") ErrorTaskForbidden = NewTaskError("forbidden") ErrorTaskNoAvailableRunners = NewTaskError("no available runner") ErrorTaskEmptySpiderId = NewTaskError("empty spider id") ErrorTaskNoNodeId = NewTaskError("no node id") ErrorTaskNodeNotFound = NewTaskError("node not found") ErrorTaskMissingRequiredOption = NewSpiderError("missing required option") ) ================================================ FILE: core/errors/user.go ================================================ package errors func NewUserError(msg string) (err error) { return NewError(ErrorPrefixUser, msg) } var ( ErrorUserInvalidType = NewUserError("invalid type") ErrorUserInvalidToken = NewUserError("invalid token") ErrorUserNotExists = NewUserError("not exists") ErrorUserNotExistsInContext = NewUserError("not exists in context") ErrorUserAlreadyExists = NewUserError("already exists") ErrorUserMismatch = NewUserError("mismatch") ErrorUserMissingRequiredFields = NewUserError("missing required fields") ErrorUserUnauthorized = NewUserError("unauthorized") ErrorUserInvalidPassword = NewUserError("invalid password (length must be no less than 5)") ) ================================================ FILE: core/event/func.go ================================================ package event func SendEvent(eventName string, data ...interface{}) { svc := NewEventService() svc.SendEvent(eventName, data...) } ================================================ FILE: core/event/options.go ================================================ package event ================================================ FILE: core/event/service.go ================================================ package event import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/thoas/go-funk" "regexp" ) var S interfaces.EventService type Service struct { keys []string includes []string excludes []string chs []*chan interfaces.EventData } func (svc *Service) Register(key, include, exclude string, ch *chan interfaces.EventData) { svc.keys = append(svc.keys, key) svc.includes = append(svc.includes, include) svc.excludes = append(svc.excludes, exclude) svc.chs = append(svc.chs, ch) } func (svc *Service) Unregister(key string) { idx := funk.IndexOfString(svc.keys, key) if idx != -1 { svc.keys = append(svc.keys[:idx], svc.keys[(idx+1):]...) svc.includes = append(svc.includes[:idx], svc.includes[(idx+1):]...) svc.excludes = append(svc.excludes[:idx], svc.excludes[(idx+1):]...) svc.chs = append(svc.chs[:idx], svc.chs[(idx+1):]...) log.Infof("[EventService] unregistered %s", key) } } func (svc *Service) SendEvent(eventName string, data ...interface{}) { for i, key := range svc.keys { // include include := svc.includes[i] matchedInclude, err := regexp.MatchString(include, eventName) if err != nil { trace.PrintError(err) continue } if !matchedInclude { continue } // exclude exclude := svc.excludes[i] matchedExclude, err := regexp.MatchString(exclude, eventName) if err != nil { trace.PrintError(err) continue } if matchedExclude { continue } // send event utils.LogDebug(fmt.Sprintf("key %s matches event %s", key, eventName)) ch := svc.chs[i] go func(ch *chan interfaces.EventData) { for _, d := range data { *ch <- &entity.EventData{ Event: eventName, Data: d, } } }(ch) } } func NewEventService() (svc interfaces.EventService) { if S != nil { return S } svc = &Service{ chs: []*chan interfaces.EventData{}, keys: []string{}, } S = svc return svc } ================================================ FILE: core/export/csv_service.go ================================================ package export import ( "context" "encoding/csv" "errors" "fmt" "github.com/ReneKroon/ttlcache" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "github.com/hashicorp/go-uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "os" "path" "sort" "strconv" "time" ) type CsvService struct { cache *ttlcache.Cache } func (svc *CsvService) GenerateId() (exportId string, err error) { exportId, err = uuid.GenerateUUID() if err != nil { return "", trace.TraceError(err) } return exportId, nil } func (svc *CsvService) Export(exportType, target string, filter interfaces.Filter) (exportId string, err error) { // generate export id exportId, err = svc.GenerateId() if err != nil { return "", err } // export export := &entity.Export{ Id: exportId, Type: exportType, Target: target, Filter: filter, Status: constants.TaskStatusRunning, StartTs: time.Now(), FileName: svc.getFileName(exportId), DownloadPath: svc.getDownloadPath(exportId), Limit: 100, } // save to cache svc.cache.Set(exportId, export) // execute export go svc.export(export) return exportId, nil } func (svc *CsvService) GetExport(exportId string) (export interfaces.Export, err error) { // get export from cache res, ok := svc.cache.Get(exportId) if !ok { return nil, trace.TraceError(errors.New("export not found")) } export = res.(interfaces.Export) return export, nil } func (svc *CsvService) export(export *entity.Export) { // check empty if export.Target == "" { err := errors.New("empty target") export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // mongo collection col := mongo.GetMongoCol(export.Target) // mongo query query, err := utils.FilterToQuery(export.Filter) if err != nil { export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // mongo cursor cur := col.Find(query, nil).GetCursor() // csv writer csvWriter, csvFile, err := svc.getCsvWriter(export) defer func() { csvWriter.Flush() _ = csvFile.Close() }() if err != nil { export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // write bom bom := []byte{0xEF, 0xBB, 0xBF} _, err = csvFile.Write(bom) if err != nil { trace.PrintError(err) return } // write csv header row columns, err := svc.getColumns(query, export) err = csvWriter.Write(columns) if err != nil { export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } csvWriter.Flush() // iterate cursor i := 0 for { // increment counter i++ // check error err := cur.Err() if err != nil { if err != mongo2.ErrNoDocuments { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) } else { // no more data export.Status = constants.TaskStatusFinished export.EndTs = time.Now() log.Infof("export finished (id: %s)", export.Id) } svc.cache.Set(export.Id, export) return } // has data if !cur.Next(context.Background()) { // no more data export.Status = constants.TaskStatusFinished export.EndTs = time.Now() log.Infof("export finished (id: %s)", export.Id) svc.cache.Set(export.Id, export) return } // convert raw data to entity var data bson.M err = cur.Decode(&data) if err != nil { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // write csv row cells cells := svc.getRowCells(columns, data) err = csvWriter.Write(cells) if err != nil { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // flush if limit reached if i >= export.Limit { csvWriter.Flush() i = 0 } } } func (svc *CsvService) getExportDir() (dir string, err error) { tempDir := os.TempDir() exportDir := path.Join(tempDir, "export", "csv") if !utils.Exists(exportDir) { err := os.MkdirAll(exportDir, 0755) if err != nil { return "", err } } return exportDir, nil } func (svc *CsvService) getFileName(exportId string) (fileName string) { return exportId + "_" + time.Now().Format("20060102150405") + ".csv" } // getDownloadPath returns the download path for the export // format: /export//_.csv func (svc *CsvService) getDownloadPath(exportId string) (downloadPath string) { exportDir, err := svc.getExportDir() if err != nil { return "" } downloadPath = path.Join(exportDir, svc.getFileName(exportId)) return downloadPath } func (svc *CsvService) getCsvWriter(export *entity.Export) (csvWriter *csv.Writer, csvFile *os.File, err error) { // open file csvFile, err = os.Create(export.DownloadPath) if err != nil { return nil, nil, trace.TraceError(err) } // create csv writer csvWriter = csv.NewWriter(csvFile) return csvWriter, csvFile, nil } func (svc *CsvService) getColumns(query bson.M, export interfaces.Export) (columns []string, err error) { // get mongo collection col := mongo.GetMongoCol(export.GetTarget()) // get 10 records var data []bson.M if err := col.Find(query, &mongo.FindOptions{Limit: 10}).All(&data); err != nil { return nil, trace.TraceError(err) } // columns set columnsSet := make(map[string]bool) for _, d := range data { for k := range d { columnsSet[k] = true } } // columns columns = make([]string, 0, len(columnsSet)) for k := range columnsSet { // skip task key if k == constants.TaskKey { continue } // skip _id if k == "_id" { continue } // append to columns columns = append(columns, k) } // order columns sort.Strings(columns) return columns, nil } func (svc *CsvService) getRowCells(columns []string, data bson.M) (cells []string) { for _, c := range columns { v, ok := data[c] if !ok { cells = append(cells, "") continue } switch v.(type) { case string: cells = append(cells, v.(string)) case time.Time: cells = append(cells, v.(time.Time).Format("2006-01-02 15:04:05")) case int: cells = append(cells, strconv.Itoa(v.(int))) case int32: cells = append(cells, strconv.Itoa(int(v.(int32)))) case int64: cells = append(cells, strconv.FormatInt(v.(int64), 10)) case float32: cells = append(cells, strconv.FormatFloat(float64(v.(float32)), 'f', -1, 32)) case float64: cells = append(cells, strconv.FormatFloat(v.(float64), 'f', -1, 64)) case bool: cells = append(cells, strconv.FormatBool(v.(bool))) case primitive.ObjectID: cells = append(cells, v.(primitive.ObjectID).Hex()) case primitive.DateTime: cells = append(cells, v.(primitive.DateTime).Time().Format("2006-01-02 15:04:05")) default: cells = append(cells, fmt.Sprintf("%v", v)) } } return cells } func NewCsvService() (svc2 interfaces.ExportService) { cache := ttlcache.NewCache() cache.SetTTL(time.Minute * 5) svc := &CsvService{ cache: cache, } return svc } var _csvService interfaces.ExportService func GetCsvService() (svc interfaces.ExportService) { if _csvService == nil { _csvService = NewCsvService() } return _csvService } ================================================ FILE: core/export/csv_service_test.go ================================================ package export import ( "encoding/csv" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/db/mongo" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "os" "strconv" "testing" "time" ) func TestCsvService_Export(t *testing.T) { // test data rows var rows []interface{} for i := 0; i < 10; i++ { data := bson.M{ "no": i, "string_field": "test", "int_field": 1, "float_field": 1.1, "bool_field": true, "time_field": time.Now(), "object_id_field": primitive.NewObjectID(), } rows = append(rows, data) } // test mongo collection name collectionName := "test_collection" // test mongo collection collection := mongo.GetMongoCol(collectionName) // delete records of test mongo collection after test t.Cleanup(func() { _ = collection.Delete(bson.M{}) }) // save test data rows to mongo collection _, err := collection.InsertMany(rows) require.Nil(t, err) // export service csvSvc := NewCsvService() // export exportId, err := csvSvc.Export(collectionName, collectionName, nil) require.Nil(t, err) // get export export, err := csvSvc.GetExport(exportId) require.Nil(t, err) require.NotNil(t, export) require.Equal(t, exportId, export.GetId()) require.NotNil(t, export.GetDownloadPath()) // wait for export to finish with timeout of 5 seconds timeout := time.After(5 * time.Second) finished := false for { if finished { break } select { case <-timeout: t.Fatal("export timeout") default: if export.GetStatus() == constants.TaskStatusFinished { finished = true continue } time.Sleep(100 * time.Millisecond) } } // export file path exportFilePath := export.GetDownloadPath() require.FileExists(t, exportFilePath) // csv file csvFile, err := os.Open(exportFilePath) require.Nil(t, err) defer csvFile.Close() // csv file reader csvFileReader := csv.NewReader(csvFile) // csv file rows csvFileRows, err := csvFileReader.ReadAll() require.Nil(t, err) require.Equal(t, len(rows), len(csvFileRows)-1) // csv file columns csvFileColumns := csvFileRows[0] // iterate csv file records and compare with test data rows for i, row := range rows { // csv file record csvFileRecord := csvFileRows[i+1] // iterate csv file columns and compare with test data row for j, column := range csvFileColumns { // csv file column value csvFileColumnValue := csvFileRecord[j] // compare csv file column value with test data row switch column { case "no": // convert int to string stringValue := fmt.Sprintf("%d", row.(bson.M)["no"].(int)) require.Equal(t, stringValue, csvFileColumnValue) case "string_field": require.Equal(t, row.(bson.M)["string_field"], csvFileColumnValue) case "int_field": // convert int to string stringValue := fmt.Sprintf("%d", row.(bson.M)["int_field"]) require.Equal(t, stringValue, csvFileColumnValue) case "float_field": // convert string to float floatValue, err := strconv.ParseFloat(csvFileColumnValue, 64) require.Nil(t, err) require.Equal(t, row.(bson.M)["float_field"].(float64), floatValue) case "bool_field": // convert bool to string stringValue := fmt.Sprintf("%t", row.(bson.M)["bool_field"]) require.Equal(t, stringValue, csvFileColumnValue) case "time_field": // convert time to string stringValue := row.(bson.M)["time_field"].(time.Time).Format("2006-01-02 15:04:05") require.Equal(t, stringValue, csvFileColumnValue) } } } } ================================================ FILE: core/export/json_service.go ================================================ package export import ( "context" "encoding/json" "errors" "github.com/ReneKroon/ttlcache" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "github.com/hashicorp/go-uuid" mongo2 "go.mongodb.org/mongo-driver/mongo" "os" "path" "time" ) type JsonService struct { cache *ttlcache.Cache } func (svc *JsonService) GenerateId() (exportId string, err error) { exportId, err = uuid.GenerateUUID() if err != nil { return "", trace.TraceError(err) } return exportId, nil } func (svc *JsonService) Export(exportType, target string, filter interfaces.Filter) (exportId string, err error) { // generate export id exportId, err = svc.GenerateId() if err != nil { return "", err } // export export := &entity.Export{ Id: exportId, Type: exportType, Target: target, Filter: filter, Status: constants.TaskStatusRunning, StartTs: time.Now(), FileName: svc.getFileName(exportId), DownloadPath: svc.getDownloadPath(exportId), Limit: 100, } // save to cache svc.cache.Set(exportId, export) // execute export go svc.export(export) return exportId, nil } func (svc *JsonService) GetExport(exportId string) (export interfaces.Export, err error) { // get export from cache res, ok := svc.cache.Get(exportId) if !ok { return nil, trace.TraceError(errors.New("export not found")) } export = res.(interfaces.Export) return export, nil } func (svc *JsonService) export(export *entity.Export) { // check empty if export.Target == "" { err := errors.New("empty target") export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // mongo collection col := mongo.GetMongoCol(export.Target) // mongo query query, err := utils.FilterToQuery(export.Filter) if err != nil { export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } // mongo cursor cur := col.Find(query, nil).GetCursor() // data var jsonData []interface{} // iterate cursor i := 0 for { // increment counter i++ // check error err := cur.Err() if err != nil { if err != mongo2.ErrNoDocuments { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) } else { // no more data export.Status = constants.TaskStatusFinished export.EndTs = time.Now() log.Infof("export finished (id: %s)", export.Id) } svc.cache.Set(export.Id, export) return } // has data if !cur.Next(context.Background()) { // no more data export.Status = constants.TaskStatusFinished export.EndTs = time.Now() log.Infof("export finished (id: %s)", export.Id) svc.cache.Set(export.Id, export) break } // convert raw data to entity var data map[string]interface{} err = cur.Decode(&data) if err != nil { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } jsonData = append(jsonData, data) } jsonBytes, err := json.Marshal(jsonData) if err != nil { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } jsonString := string(jsonBytes) f := utils.OpenFile(export.DownloadPath) _, err = f.WriteString(jsonString) if err != nil { // error export.Status = constants.TaskStatusError export.EndTs = time.Now() log.Errorf("export error (id: %s): %v", export.Id, err) trace.PrintError(err) svc.cache.Set(export.Id, export) return } } func (svc *JsonService) getExportDir() (dir string, err error) { tempDir := os.TempDir() exportDir := path.Join(tempDir, "export", "json") if !utils.Exists(exportDir) { err := os.MkdirAll(exportDir, 0755) if err != nil { return "", err } } return exportDir, nil } func (svc *JsonService) getFileName(exportId string) (fileName string) { return exportId + "_" + time.Now().Format("20060102150405") + ".json" } // getDownloadPath returns the download path for the export // format: /export//_.csv func (svc *JsonService) getDownloadPath(exportId string) (downloadPath string) { exportDir, err := svc.getExportDir() if err != nil { return "" } downloadPath = path.Join(exportDir, svc.getFileName(exportId)) return downloadPath } func NewJsonService() (svc2 interfaces.ExportService) { cache := ttlcache.NewCache() cache.SetTTL(time.Minute * 5) svc := &JsonService{ cache: cache, } return svc } var _jsonService interfaces.ExportService func GetJsonService() (svc interfaces.ExportService) { if _jsonService == nil { _jsonService = NewJsonService() } return _jsonService } ================================================ FILE: core/fs/default.go ================================================ package fs import ( "github.com/apex/log" "github.com/mitchellh/go-homedir" "github.com/spf13/viper" "path/filepath" ) func init() { rootDir, err := homedir.Dir() if err != nil { log.Warnf("cannot find home directory: %v", err) return } DefaultWorkspacePath = filepath.Join(rootDir, "crawlab_workspace") workspacePath := viper.GetString("workspace") if workspacePath == "" { viper.Set("workspace", DefaultWorkspacePath) } } var DefaultWorkspacePath string ================================================ FILE: core/fs/service_v2.go ================================================ package fs import ( "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/google/uuid" "io" "os" "path/filepath" ) type ServiceV2 struct { // settings rootPath string skipNames []string } func (svc *ServiceV2) List(path string) (files []interfaces.FsFileInfo, err error) { // Normalize the provided path normPath := filepath.Clean(path) if normPath == "." { normPath = "" } fullPath := filepath.Join(svc.rootPath, normPath) // Temporary map to hold directory information and their children dirMap := make(map[string]*entity.FsFileInfo) // Use filepath.Walk to recursively traverse directories err = filepath.Walk(fullPath, func(p string, info os.FileInfo, err error) error { if err != nil { return err } relPath, err := filepath.Rel(svc.rootPath, p) if err != nil { return err } fi := &entity.FsFileInfo{ Name: info.Name(), Path: filepath.ToSlash(relPath), FullPath: p, Extension: filepath.Ext(p), IsDir: info.IsDir(), FileSize: info.Size(), ModTime: info.ModTime(), Mode: info.Mode(), Children: nil, } // Skip files/folders matching the pattern for _, name := range svc.skipNames { if fi.Name == name { return nil } } if info.IsDir() { dirMap[p] = fi } if parentDir := filepath.Dir(p); parentDir != p && dirMap[parentDir] != nil { dirMap[parentDir].Children = append(dirMap[parentDir].Children, fi) } return nil }) if rootInfo, ok := dirMap[fullPath]; ok { for _, info := range rootInfo.GetChildren() { files = append(files, info) } } return files, err } func (svc *ServiceV2) GetFile(path string) (data []byte, err error) { return os.ReadFile(filepath.Join(svc.rootPath, path)) } func (svc *ServiceV2) GetFileInfo(path string) (file interfaces.FsFileInfo, err error) { f, err := os.Stat(filepath.Join(svc.rootPath, path)) if err != nil { return nil, err } return &entity.FsFileInfo{ Name: f.Name(), Path: path, FullPath: filepath.Join(svc.rootPath, path), Extension: filepath.Ext(path), IsDir: f.IsDir(), FileSize: f.Size(), ModTime: f.ModTime(), Mode: f.Mode(), Children: nil, }, nil } func (svc *ServiceV2) Save(path string, data []byte) (err error) { // Create directories if not exist dir := filepath.Dir(filepath.Join(svc.rootPath, path)) if _, err := os.Stat(dir); os.IsNotExist(err) { if err := os.MkdirAll(dir, 0755); err != nil { return err } } // Write file return os.WriteFile(filepath.Join(svc.rootPath, path), data, 0644) } func (svc *ServiceV2) CreateDir(path string) (err error) { return os.MkdirAll(filepath.Join(svc.rootPath, path), 0755) } func (svc *ServiceV2) Rename(path, newPath string) (err error) { oldPath := filepath.Join(svc.rootPath, path) newFullPath := filepath.Join(svc.rootPath, newPath) return os.Rename(oldPath, newFullPath) } func (svc *ServiceV2) Delete(path string) (err error) { fullPath := filepath.Join(svc.rootPath, path) return os.RemoveAll(fullPath) } func (svc *ServiceV2) Copy(path, newPath string) (err error) { srcPath := filepath.Join(svc.rootPath, path) destPath := filepath.Join(svc.rootPath, newPath) // Get source info srcInfo, err := os.Stat(srcPath) if err != nil { return err } // If source is file, copy it if !srcInfo.IsDir() { srcFile, err := os.Open(srcPath) if err != nil { return err } defer srcFile.Close() destFile, err := os.Create(destPath) if err != nil { return err } defer destFile.Close() _, err = io.Copy(destFile, srcFile) return err } else { // If source is directory, copy it recursively return utils.CopyDir(srcPath, destPath) } } func (svc *ServiceV2) Export() (resultPath string, err error) { zipFilePath := filepath.Join(os.TempDir(), uuid.New().String()+".zip") if err := utils.ZipDirectory(svc.rootPath, zipFilePath); err != nil { return "", trace.TraceError(err) } return zipFilePath, nil } func NewFsServiceV2(path string) (svc interfaces.FsServiceV2) { return &ServiceV2{ rootPath: path, skipNames: []string{".git"}, } } ================================================ FILE: core/fs/service_v2_test.go ================================================ package fs import ( "github.com/apex/log" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestServiceV2_List(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() testDir := filepath.Join(rootDir, "dir") _ = os.Mkdir(testDir, 0755) _ = os.WriteFile(filepath.Join(testDir, "file1.txt"), []byte("hello world"), 0644) _ = os.WriteFile(filepath.Join(testDir, "file2.txt"), []byte("hello again"), 0644) subDir := filepath.Join(testDir, "subdir") _ = os.Mkdir(subDir, 0755) _ = os.WriteFile(filepath.Join(subDir, "file3.txt"), []byte("subdir file"), 0644) _ = os.Mkdir(filepath.Join(testDir, "empty"), 0755) // explicitly testing empty dir inclusion svc := NewFsServiceV2(rootDir) files, err := svc.List("dir") if err != nil { t.Errorf("Failed to list files: %v", err) } // Assert correct number of items assert.Len(t, files, 4) // Use a map to verify presence and characteristics of files/directories to avoid order issues items := make(map[string]bool) for _, item := range files { items[item.GetName()] = item.GetIsDir() } _, file1Exists := items["file1.txt"] _, file2Exists := items["file2.txt"] _, subdirExists := items["subdir"] _, emptyExists := items["empty"] assert.True(t, file1Exists) assert.True(t, file2Exists) assert.True(t, subdirExists) assert.True(t, emptyExists) // Verify that the empty directory is included if subdirExists && len(files[2].GetChildren()) > 0 { assert.Equal(t, "file3.txt", files[2].GetChildren()[0].GetName()) } } func TestServiceV2_GetFile(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() expectedContent := []byte("hello world") _ = os.WriteFile(filepath.Join(rootDir, "file.txt"), expectedContent, 0644) svc := NewFsServiceV2(rootDir) content, err := svc.GetFile("file.txt") if err != nil { t.Errorf("Failed to get file: %v", err) } assert.Equal(t, expectedContent, content) } func TestServiceV2_Delete(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() filePath := filepath.Join(rootDir, "file.txt") _ = os.WriteFile(filePath, []byte("hello world"), 0644) svc := NewFsServiceV2(rootDir) // Delete the file err = svc.Delete("file.txt") if err != nil { t.Errorf("Failed to delete file: %v", err) } // Verify deletion _, err = os.Stat(filePath) assert.True(t, os.IsNotExist(err)) } func TestServiceV2_CreateDir(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Create a new directory err = svc.CreateDir("newDir") if err != nil { t.Errorf("Failed to create directory: %v", err) } // Verify the directory was created _, err = os.Stat(filepath.Join(rootDir, "newDir")) assert.NoError(t, err) } func TestServiceV2_Save(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Save a new file err = svc.Save("newFile.txt", []byte("Hello, world!")) if err != nil { t.Errorf("Failed to save file: %v", err) } // Verify the file was saved data, err := os.ReadFile(filepath.Join(rootDir, "newFile.txt")) assert.NoError(t, err) assert.Equal(t, "Hello, world!", string(data)) } func TestServiceV2_Rename(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Create a file to rename _ = os.WriteFile(filepath.Join(rootDir, "oldName.txt"), []byte("Hello, world!"), 0644) // Rename the file err = svc.Rename("oldName.txt", "newName.txt") if err != nil { t.Errorf("Failed to rename file: %v", err) } // Verify the file was renamed _, err = os.Stat(filepath.Join(rootDir, "newName.txt")) assert.NoError(t, err) } func TestServiceV2_RenameDir(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Create a directory to rename _ = os.Mkdir(filepath.Join(rootDir, "oldName"), 0755) // Rename the directory err = svc.Rename("oldName", "newName") if err != nil { t.Errorf("Failed to rename directory: %v", err) } // Verify the directory was renamed _, err = os.Stat(filepath.Join(rootDir, "newName")) assert.NoError(t, err) } func TestServiceV2_Copy(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Create a file to copy _ = os.WriteFile(filepath.Join(rootDir, "source.txt"), []byte("Hello, world!"), 0644) // Copy the file err = svc.Copy("source.txt", "copy.txt") if err != nil { t.Errorf("Failed to copy file: %v", err) } // Verify the file was copied data, err := os.ReadFile(filepath.Join(rootDir, "copy.txt")) assert.NoError(t, err) assert.Equal(t, "Hello, world!", string(data)) } func TestServiceV2_CopyDir(t *testing.T) { rootDir, err := os.MkdirTemp("", "fsTest") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer func() { err := os.RemoveAll(rootDir) // clean up if err != nil { log.Errorf("Failed to remove temp dir: %v", err) } }() svc := NewFsServiceV2(rootDir) // Create a directory to copy _ = os.Mkdir(filepath.Join(rootDir, "sourceDir"), 0755) _ = os.WriteFile(filepath.Join(rootDir, "sourceDir", "file.txt"), []byte("Hello, world!"), 0644) // Copy the directory err = svc.Copy("sourceDir", "copyDir") if err != nil { t.Errorf("Failed to copy directory: %v", err) } // Verify the directory was copied _, err = os.Stat(filepath.Join(rootDir, "copyDir")) assert.NoError(t, err) // Verify the file inside the directory was copied data, err := os.ReadFile(filepath.Join(rootDir, "copyDir", "file.txt")) assert.NoError(t, err) assert.Equal(t, "Hello, world!", string(data)) } ================================================ FILE: core/go.mod ================================================ module github.com/crawlab-team/crawlab/core go 1.22 replace ( github.com/crawlab-team/crawlab/db => ../db github.com/crawlab-team/crawlab/fs => ../fs github.com/crawlab-team/crawlab/grpc => ../grpc github.com/crawlab-team/crawlab/trace => ../trace github.com/crawlab-team/crawlab/vcs => ../vcs ) require ( github.com/PuerkitoBio/goquery v1.9.2 github.com/ReneKroon/ttlcache v1.7.0 github.com/apex/log v1.9.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/crawlab-team/crawlab/db v0.0.0-20240731075841-7fe770ae9d15 github.com/crawlab-team/crawlab/fs v0.0.0-20240731075841-7fe770ae9d15 github.com/crawlab-team/crawlab/grpc v0.0.0-20240731075841-7fe770ae9d15 github.com/crawlab-team/crawlab/trace v0.0.0-20240731075841-7fe770ae9d15 github.com/crawlab-team/crawlab/vcs v0.0.0-20240731075841-7fe770ae9d15 github.com/elastic/go-elasticsearch/v8 v8.14.0 github.com/emirpasic/gods v1.18.1 github.com/fsnotify/fsnotify v1.7.0 github.com/gin-gonic/gin v1.10.0 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 github.com/hashicorp/go-uuid v1.0.3 github.com/imroc/req v0.3.2 github.com/mitchellh/go-homedir v1.1.0 github.com/pkg/errors v0.9.1 github.com/robfig/cron/v3 v3.0.0 github.com/segmentio/kafka-go v0.4.39 github.com/shirou/gopsutil v3.21.11+incompatible github.com/smartystreets/goconvey v1.6.4 github.com/spf13/cobra v1.3.0 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/thoas/go-funk v0.9.1 github.com/upper/db/v4 v4.6.0 go.mongodb.org/mongo-driver v1.15.1 go.uber.org/dig v1.10.0 golang.org/x/oauth2 v0.21.0 google.golang.org/api v0.189.0 google.golang.org/grpc v1.65.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) require ( dario.cat/mergo v1.0.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect ) require ( cloud.google.com/go/auth v0.7.2 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/crawlab-team/goseaweedfs v0.6.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denisenkom/go-mssqldb v0.11.0 // indirect github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-git/go-git/v5 v5.12.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.10.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/segmentio/fasthash v1.0.3 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/smartystreets/assertions v1.0.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/numcpus v0.3.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/ztrue/tracerr v0.4.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.28.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/goleak v1.1.11 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: core/go.sum ================================================ 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 v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/ReneKroon/ttlcache v1.7.0 h1:8BkjFfrzVFXyrqnMtezAaJ6AHPSsVV10m6w28N/Fgkk= github.com/ReneKroon/ttlcache v1.7.0/go.mod h1:8BGGzdumrIjWxdRx8zpK6L3oGMWvIXdvB2GD1cfvd+I= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 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 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-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 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/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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 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/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crawlab-team/goseaweedfs v0.6.3 h1:f96H2QCLrZpof9na1mhIKouKrv8p32XRUyouSVm4YHU= github.com/crawlab-team/goseaweedfs v0.6.3/go.mod h1:Anqw9QErRJpTeVAVdcSfzprGzUz7OW4MVCHLJjKeO1U= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA= github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= github.com/elastic/go-elasticsearch/v8 v8.14.0 h1:1ywU8WFReLLcxE1WJqii3hTtbPUE2hc38ZK/j4mMFow= github.com/elastic/go-elasticsearch/v8 v8.14.0/go.mod h1:WRvnlGkSuZyp83M2U8El/LGXpCjYLrvlkSgkAH4O5I4= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 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= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 h1:saBP362Qm7zDdDXqv61kI4rzhmLFq3Z1gx34xpl6cWE= github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= 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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/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.1/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-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= 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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= 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.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/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-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 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-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 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/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 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.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imroc/req v0.3.2 h1:M/JkeU6RPmX+WYvT2vaaOL0K+q8ufL5LxwvJc4xeB4o= github.com/imroc/req v0.3.2/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/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/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.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.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/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= 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/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= 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/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/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 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/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 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/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/kafka-go v0.4.39 h1:75smaomhvkYRwtuOwqLsdhgCG30B82NsbdkdDfFbvrw= github.com/segmentio/kafka-go v0.4.39/go.mod h1:T0MLgygYvmqmBvC+s8aCcbVNfJN4znVne5j0Pzowp/Q= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.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/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= 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= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 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.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= 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/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/upper/db/v4 v4.6.0 h1:0VmASnqrl/XN8Ehoq++HBgZ4zRD5j3GXygW8FhP0C5I= github.com/upper/db/v4 v4.6.0/go.mod h1:2mnRcPf+RcCXmVcD+o04LYlyu3UuF7ubamJia7CkN6s= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw= github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4= github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04= github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= 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.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 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/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= 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/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 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/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/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-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= 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/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20190425163242-31fd60d6bfdc/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-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/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= 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/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI= google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8= 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.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/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-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg= google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f h1:RARaIm8pxYuxyNPbBQf5igT7XdOyCNtat1qAT2ZxjU4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 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= 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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/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= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= modernc.org/b v1.0.2/go.mod h1:fVGfCIzkZw5RsuF2A2WHbJmY7FiMIq30nP4s52uWsoY= modernc.org/db v1.0.3/go.mod h1:L4ltUg8tu2pkSJk+fKaRrXs/3EdW79ZKYQ5PfVDT53U= modernc.org/file v1.0.3/go.mod h1:CNj/pwOfCtCbqiHcXDUlHBB2vWrzdaDCWdcnjtS1+XY= modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254= modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= modernc.org/internal v1.0.2/go.mod h1:bycJAcev709ZU/47nil584PeBD+kbu8nv61ozeMso9E= modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk= modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk= modernc.org/lldb v1.0.2/go.mod h1:ovbKqyzA9H/iPwHkAOH0qJbIQVT9rlijecenxDwVUi0= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/ql v1.4.0/go.mod h1:q4c29Bgdx+iAtxx47ODW5Xo2X0PDkjSCK9NdQl6KFxc= modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/zappy v1.0.3/go.mod h1:w/Akq8ipfols/xZJdR5IYiQNOqC80qz2mVvsEwEbkiI= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= ================================================ FILE: core/grpc/client/client.go ================================================ package client import ( "context" "encoding/json" "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/grpc/middlewares" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" grpc2 "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" "io" "time" ) type Client struct { // dependencies nodeCfgSvc interfaces.NodeConfigService // settings cfgPath string address interfaces.Address timeout time.Duration subscribeType string handleMessage bool // internals conn *grpc.ClientConn stream grpc2.NodeService_SubscribeClient msgCh chan *grpc2.StreamMessage err error // grpc clients ModelDelegateClient grpc2.ModelDelegateClient ModelBaseServiceClient grpc2.ModelBaseServiceClient NodeClient grpc2.NodeServiceClient TaskClient grpc2.TaskServiceClient MessageClient grpc2.MessageServiceClient } func (c *Client) Init() (err error) { // do nothing return nil } func (c *Client) Start() (err error) { // connect if err := c.connect(); err != nil { return err } // register rpc services if err := c.Register(); err != nil { return err } // subscribe if err := c.subscribe(); err != nil { return err } // handle stream message if c.handleMessage { go c.handleStreamMessage() } return nil } func (c *Client) Stop() (err error) { // skip if connection is nil if c.conn == nil { return nil } // grpc server address address := c.address.String() // unsubscribe if err := c.unsubscribe(); err != nil { return err } log.Infof("grpc client unsubscribed from %s", address) // close connection if err := c.conn.Close(); err != nil { return err } log.Infof("grpc client disconnected from %s", address) return nil } func (c *Client) Register() (err error) { // model delegate c.ModelDelegateClient = grpc2.NewModelDelegateClient(c.conn) // model base service c.ModelBaseServiceClient = grpc2.NewModelBaseServiceClient(c.conn) // node c.NodeClient = grpc2.NewNodeServiceClient(c.conn) // task c.TaskClient = grpc2.NewTaskServiceClient(c.conn) // message c.MessageClient = grpc2.NewMessageServiceClient(c.conn) // log log.Infof("[GrpcClient] grpc client registered client services") log.Debugf("[GrpcClient] ModelDelegateClient: %v", c.ModelDelegateClient) log.Debugf("[GrpcClient] ModelBaseServiceClient: %v", c.ModelBaseServiceClient) log.Debugf("[GrpcClient] NodeClient: %v", c.NodeClient) log.Debugf("[GrpcClient] TaskClient: %v", c.TaskClient) log.Debugf("[GrpcClient] MessageClient: %v", c.MessageClient) return nil } func (c *Client) GetModelDelegateClient() (res grpc2.ModelDelegateClient) { return c.ModelDelegateClient } func (c *Client) GetModelBaseServiceClient() (res grpc2.ModelBaseServiceClient) { return c.ModelBaseServiceClient } func (c *Client) GetNodeClient() grpc2.NodeServiceClient { return c.NodeClient } func (c *Client) GetTaskClient() grpc2.TaskServiceClient { return c.TaskClient } func (c *Client) GetMessageClient() grpc2.MessageServiceClient { return c.MessageClient } func (c *Client) SetAddress(address interfaces.Address) { c.address = address } func (c *Client) SetTimeout(timeout time.Duration) { c.timeout = timeout } func (c *Client) SetSubscribeType(value string) { c.subscribeType = value } func (c *Client) SetHandleMessage(handleMessage bool) { c.handleMessage = handleMessage } func (c *Client) Context() (ctx context.Context, cancel context.CancelFunc) { return context.WithTimeout(context.Background(), c.timeout) } func (c *Client) NewRequest(d interface{}) (req *grpc2.Request) { return &grpc2.Request{ NodeKey: c.nodeCfgSvc.GetNodeKey(), Data: c.getRequestData(d), } } func (c *Client) GetConfigPath() (path string) { return c.cfgPath } func (c *Client) SetConfigPath(path string) { c.cfgPath = path } func (c *Client) NewModelBaseServiceRequest(id interfaces.ModelId, params interfaces.GrpcBaseServiceParams) (req *grpc2.Request, err error) { data, err := json.Marshal(params) if err != nil { return nil, trace.TraceError(err) } msg := &entity.GrpcBaseServiceMessage{ ModelId: id, Data: data, } return c.NewRequest(msg), nil } func (c *Client) GetMessageChannel() (msgCh chan *grpc2.StreamMessage) { return c.msgCh } func (c *Client) Restart() (err error) { if c.needRestart() { return c.Start() } return nil } func (c *Client) IsStarted() (res bool) { return c.conn != nil } func (c *Client) IsClosed() (res bool) { if c.conn != nil { return c.conn.GetState() == connectivity.Shutdown } return false } func (c *Client) Err() (err error) { return c.err } func (c *Client) GetStream() (stream grpc2.NodeService_SubscribeClient) { return c.stream } func (c *Client) connect() (err error) { return backoff.RetryNotify(c._connect, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client connect")) } func (c *Client) _connect() (err error) { // grpc server address address := c.address.String() // timeout context ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() // connection // TODO: configure dial options var opts []grpc.DialOption opts = append(opts, grpc.WithInsecure()) opts = append(opts, grpc.WithBlock()) opts = append(opts, grpc.WithChainUnaryInterceptor(middlewares.GetAuthTokenUnaryChainInterceptor(c.nodeCfgSvc))) opts = append(opts, grpc.WithChainStreamInterceptor(middlewares.GetAuthTokenStreamChainInterceptor(c.nodeCfgSvc))) c.conn, err = grpc.DialContext(ctx, address, opts...) if err != nil { _ = trace.TraceError(err) return errors.ErrorGrpcClientFailedToStart } log.Infof("[GrpcClient] grpc client connected to %s", address) return nil } func (c *Client) subscribe() (err error) { var op func() error switch c.subscribeType { case constants.GrpcSubscribeTypeNode: op = c._subscribeNode default: return errors.ErrorGrpcInvalidType } return backoff.RetryNotify(op, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client subscribe")) } func (c *Client) _subscribeNode() (err error) { req := c.NewRequest(&entity.NodeInfo{ Key: c.nodeCfgSvc.GetNodeKey(), IsMaster: false, }) c.stream, err = c.GetNodeClient().Subscribe(context.Background(), req) if err != nil { return trace.TraceError(err) } // log log.Infof("[GrpcClient] grpc client subscribed to remote server") return nil } func (c *Client) unsubscribe() (err error) { req := c.NewRequest(&entity.NodeInfo{ Key: c.nodeCfgSvc.GetNodeKey(), IsMaster: false, }) if _, err = c.GetNodeClient().Unsubscribe(context.Background(), req); err != nil { return trace.TraceError(err) } return nil } func (c *Client) handleStreamMessage() { log.Infof("[GrpcClient] start handling stream message...") for { // resubscribe if stream is set to nil if c.stream == nil { if err := backoff.RetryNotify(c.subscribe, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client subscribe")); err != nil { log.Errorf("subscribe") return } } // receive stream message msg, err := c.stream.Recv() log.Debugf("[GrpcClient] received message: %v", msg) if err != nil { // set error c.err = err // end if err == io.EOF { log.Infof("[GrpcClient] received EOF signal, disconnecting") return } // connection closed if c.IsClosed() { return } // error trace.PrintError(err) c.stream = nil time.Sleep(1 * time.Second) continue } // send stream message to channel c.msgCh <- msg // reset error c.err = nil } } func (c *Client) needRestart() bool { switch c.conn.GetState() { case connectivity.Shutdown, connectivity.TransientFailure: return true case connectivity.Idle, connectivity.Connecting, connectivity.Ready: return false default: return false } } func (c *Client) getRequestData(d interface{}) (data []byte) { if d == nil { return data } switch d.(type) { case []byte: data = d.([]byte) default: var err error data, err = json.Marshal(d) if err != nil { panic(err) } } return data } func NewClient() (res interfaces.GrpcClient, err error) { // client client := &Client{ address: entity.NewAddress(&entity.AddressOptions{ Host: constants.DefaultGrpcClientRemoteHost, Port: constants.DefaultGrpcClientRemotePort, }), timeout: 10 * time.Second, msgCh: make(chan *grpc2.StreamMessage), subscribeType: constants.GrpcSubscribeTypeNode, handleMessage: true, } if viper.GetString("grpc.address") != "" { client.address, err = entity.NewAddressFromString(viper.GetString("grpc.address")) if err != nil { return nil, trace.TraceError(err) } } // dependency injection if err := container.GetContainer().Invoke(func(nodeCfgSvc interfaces.NodeConfigService) { client.nodeCfgSvc = nodeCfgSvc }); err != nil { return nil, err } // init if err := client.Init(); err != nil { return nil, err } return client, nil } var _client interfaces.GrpcClient func GetClient() (c interfaces.GrpcClient, err error) { if _client != nil { return _client, nil } _client, err = createClient() if err != nil { return nil, err } return _client, nil } func createClient() (client2 interfaces.GrpcClient, err error) { if err := container.GetContainer().Invoke(func(client interfaces.GrpcClient) { client2 = client }); err != nil { return nil, trace.TraceError(err) } return client2, nil } ================================================ FILE: core/grpc/client/client_v2.go ================================================ package client import ( "context" "encoding/json" "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/grpc/middlewares" "github.com/crawlab-team/crawlab/core/interfaces" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/utils" grpc2 "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials/insecure" "io" "sync" "time" ) type GrpcClientV2 struct { // dependencies nodeCfgSvc interfaces.NodeConfigService // settings address interfaces.Address timeout time.Duration // internals conn *grpc.ClientConn stream grpc2.NodeService_SubscribeClient msgCh chan *grpc2.StreamMessage err error once sync.Once // clients NodeClient grpc2.NodeServiceClient TaskClient grpc2.TaskServiceClient ModelBaseServiceV2Client grpc2.ModelBaseServiceV2Client DependenciesClient grpc2.DependenciesServiceV2Client MetricsClient grpc2.MetricsServiceV2Client } func (c *GrpcClientV2) Start() (err error) { c.once.Do(func() { // connect err = c.connect() if err != nil { return } // register rpc services c.Register() // subscribe err = c.subscribe() if err != nil { return } // handle stream message go c.handleStreamMessage() }) return err } func (c *GrpcClientV2) Stop() (err error) { // skip if connection is nil if c.conn == nil { return nil } // grpc server address address := c.address.String() // unsubscribe if err := c.unsubscribe(); err != nil { return err } log.Infof("grpc client unsubscribed from %s", address) // close connection if err := c.conn.Close(); err != nil { return err } log.Infof("grpc client disconnected from %s", address) return nil } func (c *GrpcClientV2) Register() { c.NodeClient = grpc2.NewNodeServiceClient(c.conn) c.ModelBaseServiceV2Client = grpc2.NewModelBaseServiceV2Client(c.conn) c.TaskClient = grpc2.NewTaskServiceClient(c.conn) c.DependenciesClient = grpc2.NewDependenciesServiceV2Client(c.conn) c.MetricsClient = grpc2.NewMetricsServiceV2Client(c.conn) } func (c *GrpcClientV2) Context() (ctx context.Context, cancel context.CancelFunc) { return context.WithTimeout(context.Background(), c.timeout) } func (c *GrpcClientV2) NewRequest(d interface{}) (req *grpc2.Request) { return &grpc2.Request{ NodeKey: c.nodeCfgSvc.GetNodeKey(), Data: c.getRequestData(d), } } func (c *GrpcClientV2) IsStarted() (res bool) { return c.conn != nil } func (c *GrpcClientV2) IsClosed() (res bool) { if c.conn != nil { return c.conn.GetState() == connectivity.Shutdown } return false } func (c *GrpcClientV2) GetMessageChannel() (msgCh chan *grpc2.StreamMessage) { return c.msgCh } func (c *GrpcClientV2) getRequestData(d interface{}) (data []byte) { if d == nil { return data } switch d.(type) { case []byte: data = d.([]byte) default: var err error data, err = json.Marshal(d) if err != nil { panic(err) } } return data } func (c *GrpcClientV2) unsubscribe() (err error) { req := c.NewRequest(&entity.NodeInfo{ Key: c.nodeCfgSvc.GetNodeKey(), IsMaster: false, }) if _, err = c.NodeClient.Unsubscribe(context.Background(), req); err != nil { return trace.TraceError(err) } return nil } func (c *GrpcClientV2) connect() (err error) { op := func() error { // grpc server address address := c.address.String() // timeout context ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() // connection // TODO: configure dial options var opts []grpc.DialOption opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) opts = append(opts, grpc.WithBlock()) opts = append(opts, grpc.WithChainUnaryInterceptor(middlewares.GetAuthTokenUnaryChainInterceptor(c.nodeCfgSvc))) opts = append(opts, grpc.WithChainStreamInterceptor(middlewares.GetAuthTokenStreamChainInterceptor(c.nodeCfgSvc))) c.conn, err = grpc.DialContext(ctx, address, opts...) if err != nil { _ = trace.TraceError(err) return errors.ErrorGrpcClientFailedToStart } log.Infof("[GrpcClient] grpc client connected to %s", address) return nil } return backoff.RetryNotify(op, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client connect")) } func (c *GrpcClientV2) subscribe() (err error) { op := func() error { req := c.NewRequest(&entity.NodeInfo{ Key: c.nodeCfgSvc.GetNodeKey(), IsMaster: false, }) c.stream, err = c.NodeClient.Subscribe(context.Background(), req) if err != nil { return trace.TraceError(err) } // log log.Infof("[GrpcClient] grpc client subscribed to remote server") return nil } return backoff.RetryNotify(op, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client subscribe")) } func (c *GrpcClientV2) handleStreamMessage() { log.Infof("[GrpcClient] start handling stream message...") for { // resubscribe if stream is set to nil if c.stream == nil { if err := backoff.RetryNotify(c.subscribe, backoff.NewExponentialBackOff(), utils.BackoffErrorNotify("grpc client subscribe")); err != nil { log.Errorf("subscribe") return } } // receive stream message msg, err := c.stream.Recv() log.Debugf("[GrpcClient] received message: %v", msg) if err != nil { // set error c.err = err // end if err == io.EOF { log.Infof("[GrpcClient] received EOF signal, disconnecting") return } // connection closed if c.IsClosed() { return } // error trace.PrintError(err) c.stream = nil time.Sleep(1 * time.Second) continue } // send stream message to channel c.msgCh <- msg // reset error c.err = nil } } func newGrpcClientV2() (c *GrpcClientV2) { client := &GrpcClientV2{ address: entity.NewAddress(&entity.AddressOptions{ Host: constants.DefaultGrpcClientRemoteHost, Port: constants.DefaultGrpcClientRemotePort, }), timeout: 10 * time.Second, msgCh: make(chan *grpc2.StreamMessage), } client.nodeCfgSvc = nodeconfig.GetNodeConfigService() if viper.GetString("grpc.address") != "" { address, err := entity.NewAddressFromString(viper.GetString("grpc.address")) if err != nil { log.Errorf("failed to parse grpc address: %s", viper.GetString("grpc.address")) panic(err) } client.address = address } return client } var clientV2 *GrpcClientV2 var clientV2Once sync.Once func GetGrpcClientV2() *GrpcClientV2 { clientV2Once.Do(func() { clientV2 = newGrpcClientV2() }) return clientV2 } ================================================ FILE: core/grpc/client/options.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Option func(client interfaces.GrpcClient) func WithConfigPath(path string) Option { return func(c interfaces.GrpcClient) { c.SetConfigPath(path) } } func WithAddress(address interfaces.Address) Option { return func(c interfaces.GrpcClient) { c.SetAddress(address) } } func WithTimeout(timeout time.Duration) Option { return func(c interfaces.GrpcClient) { } } func WithSubscribeType(subscribeType string) Option { return func(c interfaces.GrpcClient) { c.SetSubscribeType(subscribeType) } } func WithHandleMessage(handleMessage bool) Option { return func(c interfaces.GrpcClient) { c.SetHandleMessage(handleMessage) } } type PoolOption func(p interfaces.GrpcClientPool) func WithPoolConfigPath(path string) PoolOption { return func(c interfaces.GrpcClientPool) { c.SetConfigPath(path) } } func WithPoolSize(size int) PoolOption { return func(c interfaces.GrpcClientPool) { c.SetSize(size) } } ================================================ FILE: core/grpc/client/pool.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/trace" "github.com/emirpasic/gods/lists/arraylist" "math/rand" ) type Pool struct { // settings size int cfgPath string // internals clients *arraylist.List } func (p *Pool) GetConfigPath() (path string) { return p.cfgPath } func (p *Pool) SetConfigPath(path string) { p.cfgPath = path } func (p *Pool) Init() (err error) { for i := 0; i < p.size; i++ { if err := p.NewClient(); err != nil { return err } } return nil } func (p *Pool) NewClient() (err error) { c, err := NewClient() if err != nil { return trace.TraceError(err) } if err := c.Start(); err != nil { return err } p.clients.Add(c) return nil } func (p *Pool) GetClient() (c interfaces.GrpcClient, err error) { idx := p.getRandomIndex() res, ok := p.clients.Get(idx) if !ok { return nil, trace.TraceError(errors.ErrorGrpcClientNotExists) } c, ok = res.(interfaces.GrpcClient) if !ok { return nil, trace.TraceError(errors.ErrorGrpcInvalidType) } return c, nil } func (p *Pool) SetSize(size int) { p.size = size } func (p *Pool) getRandomIndex() (idx int) { return rand.Intn(p.clients.Size()) } func NewPool(opts ...PoolOption) (p interfaces.GrpcClientPool, err error) { // pool p = &Pool{ size: 1, clients: arraylist.New(), } // apply options for _, opt := range opts { opt(p) } // initialize if err := p.Init(); err != nil { return nil, err } return p, nil } ================================================ FILE: core/grpc/client/utils_proto.go ================================================ package client import grpc2 "github.com/crawlab-team/crawlab/grpc" var EmptyRequest = &grpc2.Request{} ================================================ FILE: core/grpc/middlewares/auth_token.go ================================================ package middlewares import ( "context" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/grpc-ecosystem/go-grpc-middleware/auth" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) func GetAuthTokenFunc(nodeCfgSvc interfaces.NodeConfigService) grpc_auth.AuthFunc { return func(ctx context.Context) (ctx2 context.Context, err error) { // authentication (token verification) md, ok := metadata.FromIncomingContext(ctx) if !ok { return nil, errors.ErrorGrpcUnauthorized } // auth key from incoming context res, ok := md[constants.GrpcHeaderAuthorization] if !ok { return ctx, errors.ErrorGrpcUnauthorized } if len(res) != 1 { return ctx, errors.ErrorGrpcUnauthorized } authKey := res[0] // validate svrAuthKey := nodeCfgSvc.GetAuthKey() if authKey != svrAuthKey { return ctx, errors.ErrorGrpcUnauthorized } return ctx, nil } } func GetAuthTokenUnaryChainInterceptor(nodeCfgSvc interfaces.NodeConfigService) grpc.UnaryClientInterceptor { // set auth key md := metadata.Pairs(constants.GrpcHeaderAuthorization, nodeCfgSvc.GetAuthKey()) //header := metadata.MD{} //header[constants.GrpcHeaderAuthorization] = []string{nodeCfgSvc.GetAuthKey()} return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { ctx = metadata.NewOutgoingContext(context.Background(), md) //opts = append(opts, grpc.Header(&header)) return invoker(ctx, method, req, reply, cc, opts...) } } func GetAuthTokenStreamChainInterceptor(nodeCfgSvc interfaces.NodeConfigService) grpc.StreamClientInterceptor { // set auth key md := metadata.Pairs(constants.GrpcHeaderAuthorization, nodeCfgSvc.GetAuthKey()) //header := metadata.MD{} //header[constants.GrpcHeaderAuthorization] = []string{nodeCfgSvc.GetAuthKey()} return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { ctx = metadata.NewOutgoingContext(context.Background(), md) //opts = append(opts, grpc.Header(&header)) s, err := streamer(ctx, desc, cc, method, opts...) if err != nil { return nil, err } return s, nil } } ================================================ FILE: core/grpc/payload/model_service_v2_payload.go ================================================ package payload import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type ModelServiceV2Payload struct { Type string `json:"type,omitempty"` Id primitive.ObjectID `json:"_id,omitempty"` Query bson.M `json:"query,omitempty"` FindOptions *mongo.FindOptions `json:"find_options,omitempty"` Model any `json:"model,omitempty"` Update bson.M `json:"update,omitempty"` Models []any `json:"models,omitempty"` } ================================================ FILE: core/grpc/server/dependencies_server_v2.go ================================================ package server import ( "context" "errors" "github.com/apex/log" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" mongo2 "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "io" "sync" "time" ) type DependenciesServerV2 struct { grpc.UnimplementedDependenciesServiceV2Server mu *sync.Mutex streams map[string]*grpc.DependenciesServiceV2_ConnectServer } func (svr DependenciesServerV2) Connect(req *grpc.DependenciesServiceV2ConnectRequest, stream grpc.DependenciesServiceV2_ConnectServer) (err error) { svr.mu.Lock() svr.streams[req.NodeKey] = &stream svr.mu.Unlock() log.Info("[DependenciesServerV2] connected: " + req.NodeKey) // Keep this scope alive because once this scope exits - the stream is closed for { select { case <-stream.Context().Done(): log.Info("[DependenciesServerV2] disconnected: " + req.NodeKey) return nil } } } func (svr DependenciesServerV2) Sync(ctx context.Context, request *grpc.DependenciesServiceV2SyncRequest) (response *grpc.Response, err error) { n, err := service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": request.NodeKey}, nil) if err != nil { return nil, err } depsDb, err := service.NewModelServiceV2[models2.DependencyV2]().GetMany(bson.M{ "node_id": n.Id, "type": request.Lang, }, nil) if err != nil { if !errors.Is(err, mongo.ErrNoDocuments) { log.Errorf("[DependenciesServiceV2] get dependencies from db error: %v", err) return nil, err } } depsDbMap := make(map[string]*models2.DependencyV2) for _, d := range depsDb { depsDbMap[d.Name] = &d } var depsToInsert []models2.DependencyV2 depsMap := make(map[string]*models2.DependencyV2) for _, dep := range request.Dependencies { d := models2.DependencyV2{ Name: dep.Name, NodeId: n.Id, Type: request.Lang, Version: dep.Version, } d.SetCreatedAt(time.Now()) depsMap[d.Name] = &d _, ok := depsDbMap[d.Name] if !ok { depsToInsert = append(depsToInsert, d) } } var depIdsToDelete []primitive.ObjectID for _, d := range depsDb { _, ok := depsMap[d.Name] if !ok { depIdsToDelete = append(depIdsToDelete, d.Id) } } err = mongo2.RunTransaction(func(ctx mongo.SessionContext) (err error) { if len(depIdsToDelete) > 0 { err = service.NewModelServiceV2[models2.DependencyV2]().DeleteMany(bson.M{ "_id": bson.M{"$in": depIdsToDelete}, }) if err != nil { log.Errorf("[DependenciesServerV2] delete dependencies in db error: %v", err) trace.PrintError(err) return err } } if len(depsToInsert) > 0 { _, err = service.NewModelServiceV2[models2.DependencyV2]().InsertMany(depsToInsert) if err != nil { log.Errorf("[DependenciesServerV2] insert dependencies in db error: %v", err) trace.PrintError(err) return err } } return nil }) return nil, err } func (svr DependenciesServerV2) UpdateTaskLog(stream grpc.DependenciesServiceV2_UpdateTaskLogServer) (err error) { var t *models2.DependencyTaskV2 for { req, err := stream.Recv() if err == io.EOF { // all messages have been received return stream.SendAndClose(&grpc.Response{Message: "update task log finished"}) } if err != nil { return err } taskId, err := primitive.ObjectIDFromHex(req.TaskId) if err != nil { return err } if t == nil { t, err = service.NewModelServiceV2[models2.DependencyTaskV2]().GetById(taskId) if err != nil { return err } } var logs []models2.DependencyLogV2 for _, line := range req.LogLines { l := models2.DependencyLogV2{ TaskId: taskId, Content: line, } l.SetCreated(t.CreatedBy) logs = append(logs, l) } _, err = service.NewModelServiceV2[models2.DependencyLogV2]().InsertMany(logs) if err != nil { return err } } } func (svr DependenciesServerV2) GetStream(key string) (stream *grpc.DependenciesServiceV2_ConnectServer, err error) { svr.mu.Lock() defer svr.mu.Unlock() stream, ok := svr.streams[key] if !ok { return nil, errors.New("stream not found") } return stream, nil } func NewDependenciesServerV2() *DependenciesServerV2 { return &DependenciesServerV2{ mu: new(sync.Mutex), streams: make(map[string]*grpc.DependenciesServiceV2_ConnectServer), } } var depSvc *DependenciesServerV2 func GetDependenciesServerV2() *DependenciesServerV2 { if depSvc != nil { return depSvc } depSvc = NewDependenciesServerV2() return depSvc } ================================================ FILE: core/grpc/server/message_server.go ================================================ package server import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/service" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "io" ) type MessageServer struct { grpc.UnimplementedMessageServiceServer // dependencies modelSvc service.ModelService cfgSvc interfaces.NodeConfigService // internals server interfaces.GrpcServer } func (svr MessageServer) Connect(stream grpc.MessageService_ConnectServer) (err error) { finished := make(chan bool) for { msg, err := stream.Recv() nodeKey := "unknown node key" if msg != nil { nodeKey = msg.NodeKey } if err == io.EOF { log.Infof("[MessageServer] received signal EOF from node[%s], now quit", nodeKey) return nil } if err != nil { log.Errorf("[MessageServer] receiving message error from node[%s]: %v", nodeKey, err) return err } switch msg.Code { case grpc.StreamMessageCode_CONNECT: log.Infof("[MessageServer] received connect request from node[%s], key: %s", nodeKey, msg.Key) svr.server.SetSubscribe(msg.Key, &entity.GrpcSubscribe{ Stream: stream, Finished: finished, }) case grpc.StreamMessageCode_DISCONNECT: log.Infof("[MessageServer] received disconnect request from node[%s], key: %s", nodeKey, msg.Key) svr.server.DeleteSubscribe(msg.Key) return nil case grpc.StreamMessageCode_SEND: log.Debugf("[MessageServer] received send request from node[%s] to %s", nodeKey, msg.To) sub, err := svr.server.GetSubscribe(msg.To) if err != nil { return err } svr.redirectMessage(sub, msg) } } } func (svr MessageServer) redirectMessage(sub interfaces.GrpcSubscribe, msg *grpc.StreamMessage) { stream := sub.GetStream() if stream == nil { trace.PrintError(errors.ErrorGrpcStreamNotFound) return } log.Debugf("[MessageServer] redirect message: %v", msg) if err := stream.Send(msg); err != nil { trace.PrintError(err) return } } func NewMessageServer() (res *MessageServer, err error) { // message server svr := &MessageServer{} // dependency injection if err := container.GetContainer().Invoke(func( modelSvc service.ModelService, cfgSvc interfaces.NodeConfigService, ) { svr.modelSvc = modelSvc svr.cfgSvc = cfgSvc }); err != nil { return nil, err } return svr, nil } ================================================ FILE: core/grpc/server/metrics_server_v2.go ================================================ package server import ( "context" "github.com/apex/log" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/grpc" "go.mongodb.org/mongo-driver/bson" "sync" "time" ) type MetricsServerV2 struct { grpc.UnimplementedMetricsServiceV2Server } func (svr MetricsServerV2) Send(_ context.Context, req *grpc.MetricsServiceV2SendRequest) (res *grpc.Response, err error) { log.Info("[MetricsServerV2] received metric from node: " + req.NodeKey) n, err := service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": req.NodeKey}, nil) if err != nil { log.Errorf("[MetricsServerV2] error getting node: %v", err) return HandleError(err) } metric := models2.MetricV2{ Type: req.Type, NodeId: n.Id, CpuUsagePercent: req.CpuUsagePercent, TotalMemory: req.TotalMemory, AvailableMemory: req.AvailableMemory, UsedMemory: req.UsedMemory, UsedMemoryPercent: req.UsedMemoryPercent, TotalDisk: req.TotalDisk, AvailableDisk: req.AvailableDisk, UsedDisk: req.UsedDisk, UsedDiskPercent: req.UsedDiskPercent, DiskReadBytesRate: req.DiskReadBytesRate, DiskWriteBytesRate: req.DiskWriteBytesRate, NetworkBytesSentRate: req.NetworkBytesSentRate, NetworkBytesRecvRate: req.NetworkBytesRecvRate, } metric.CreatedAt = time.Unix(req.Timestamp, 0) _, err = service.NewModelServiceV2[models2.MetricV2]().InsertOne(metric) if err != nil { log.Errorf("[MetricsServerV2] error inserting metric: %v", err) return HandleError(err) } return HandleSuccess() } func newMetricsServerV2() *MetricsServerV2 { return &MetricsServerV2{} } var metricsServerV2 *MetricsServerV2 var metricsServerV2Once = &sync.Once{} func GetMetricsServerV2() *MetricsServerV2 { if metricsServerV2 != nil { return metricsServerV2 } metricsServerV2Once.Do(func() { metricsServerV2 = newMetricsServerV2() }) return metricsServerV2 } ================================================ FILE: core/grpc/server/model_base_service_binder.go ================================================ package server import ( "encoding/json" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" ) func NewModelBaseServiceBinder(req *grpc.Request) (b *ModelBaseServiceBinder) { return &ModelBaseServiceBinder{ req: req, msg: &entity.GrpcBaseServiceMessage{}, } } type ModelBaseServiceBinder struct { req *grpc.Request msg interfaces.GrpcModelBaseServiceMessage } func (b *ModelBaseServiceBinder) Bind() (res *entity.GrpcBaseServiceParams, err error) { if err := b.bindBaseServiceMessage(); err != nil { return nil, err } params := &entity.GrpcBaseServiceParams{} return b.process(params) } func (b *ModelBaseServiceBinder) MustBind() (res interface{}) { res, err := b.Bind() if err != nil { panic(err) } return res } func (b *ModelBaseServiceBinder) BindWithBaseServiceMessage() (params *entity.GrpcBaseServiceParams, msg interfaces.GrpcModelBaseServiceMessage, err error) { if err := json.Unmarshal(b.req.Data, b.msg); err != nil { return nil, nil, err } params, err = b.Bind() if err != nil { return nil, nil, err } return params, b.msg, nil } func (b *ModelBaseServiceBinder) process(params *entity.GrpcBaseServiceParams) (res *entity.GrpcBaseServiceParams, err error) { if err := json.Unmarshal(b.msg.GetData(), params); err != nil { return nil, trace.TraceError(err) } return params, nil } func (b *ModelBaseServiceBinder) bindBaseServiceMessage() (err error) { return json.Unmarshal(b.req.Data, b.msg) } ================================================ FILE: core/grpc/server/model_base_service_server.go ================================================ package server import ( "context" "encoding/json" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" ) type ModelBaseServiceServer struct { grpc.UnimplementedModelBaseServiceServer // dependencies modelSvc interfaces.ModelService } func (svr ModelBaseServiceServer) GetById(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { return svc.GetById(params.Id) }) } func (svr ModelBaseServiceServer) Get(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { return svc.Get(utils.NormalizeBsonMObjectId(params.Query), params.FindOptions) }) } func (svr ModelBaseServiceServer) GetList(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { list, err := svc.GetList(utils.NormalizeBsonMObjectId(params.Query), params.FindOptions) if err != nil { return nil, err } data, err := json.Marshal(list) if err != nil { return nil, err } return data, nil }) } func (svr ModelBaseServiceServer) DeleteById(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.DeleteById(params.Id, params.User) return nil, err }) } func (svr ModelBaseServiceServer) Delete(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.Delete(utils.NormalizeBsonMObjectId(params.Query), params.User) return nil, err }) } func (svr ModelBaseServiceServer) DeleteList(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.DeleteList(utils.NormalizeBsonMObjectId(params.Query), params.User) return nil, err }) } func (svr ModelBaseServiceServer) ForceDeleteList(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.ForceDeleteList(utils.NormalizeBsonMObjectId(params.Query), params.User) return nil, err }) } func (svr ModelBaseServiceServer) UpdateById(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.UpdateById(params.Id, params.Update) return nil, err }) } func (svr ModelBaseServiceServer) Update(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.Update(utils.NormalizeBsonMObjectId(params.Query), params.Update, params.Fields, params.User) return nil, err }) } func (svr ModelBaseServiceServer) UpdateDoc(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.UpdateDoc(utils.NormalizeBsonMObjectId(params.Query), params.Doc, params.Fields, params.User) return nil, err }) } func (svr ModelBaseServiceServer) Insert(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { err := svc.Insert(params.User, params.Docs...) return nil, err }) } func (svr ModelBaseServiceServer) Count(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return svr.handleRequest(req, func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) { return svc.Count(utils.NormalizeBsonMObjectId(params.Query)) }) } func (svr ModelBaseServiceServer) handleRequest(req *grpc.Request, handle handleBaseServiceRequest) (res *grpc.Response, err error) { params, msg, err := NewModelBaseServiceBinder(req).BindWithBaseServiceMessage() if err != nil { return HandleError(err) } svc := svr.modelSvc.GetBaseService(msg.GetModelId()) d, err := handle(params, svc) if err != nil { return HandleError(err) } if d == nil { return HandleSuccess() } return HandleSuccessWithData(d) } type handleBaseServiceRequest func(params *entity.GrpcBaseServiceParams, svc interfaces.ModelBaseService) (interface{}, error) func NewModelBaseServiceServer() (svr2 *ModelBaseServiceServer, err error) { svr := &ModelBaseServiceServer{} // dependency injection if err := container.GetContainer().Invoke(func(modelSvc service.ModelService) { svr.modelSvc = modelSvc }); err != nil { return nil, trace.TraceError(err) } return svr, nil } ================================================ FILE: core/grpc/server/model_base_service_v2_server.go ================================================ package server import ( "context" "encoding/json" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/grpc" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "reflect" ) var ( typeNameColNameMap = make(map[string]string) typeOneNameModelMap = make(map[string]any) typeOneInstances = []any{ *new(models2.TestModelV2), *new(models2.DataCollectionV2), *new(models2.DatabaseV2), *new(models2.DatabaseMetricV2), *new(models2.DependencyV2), *new(models2.DependencyLogV2), *new(models2.DependencySettingV2), *new(models2.DependencyTaskV2), *new(models2.EnvironmentV2), *new(models2.GitV2), *new(models2.MetricV2), *new(models2.NodeV2), *new(models2.NotificationChannelV2), *new(models2.NotificationRequestV2), *new(models2.NotificationSettingV2), *new(models2.PermissionV2), *new(models2.ProjectV2), *new(models2.RolePermissionV2), *new(models2.RoleV2), *new(models2.ScheduleV2), *new(models2.SettingV2), *new(models2.SpiderV2), *new(models2.SpiderStatV2), *new(models2.TaskQueueItemV2), *new(models2.TaskStatV2), *new(models2.TaskV2), *new(models2.TokenV2), *new(models2.UserRoleV2), *new(models2.UserV2), } ) func init() { for _, v := range typeOneInstances { t := reflect.TypeOf(v) typeName := t.Name() colName := service.GetCollectionNameByInstance(v) typeNameColNameMap[typeName] = colName typeOneNameModelMap[typeName] = v } } func GetOneInstanceModel(typeName string) any { return typeOneNameModelMap[typeName] } type ModelBaseServiceServerV2 struct { grpc.UnimplementedModelBaseServiceV2Server } func (svr ModelBaseServiceServerV2) GetById(_ context.Context, req *grpc.ModelServiceV2GetByIdRequest) (res *grpc.Response, err error) { id, err := primitive.ObjectIDFromHex(req.Id) if err != nil { return HandleError(err) } modelSvc := service.NewModelServiceV2WithColName[bson.M](typeNameColNameMap[req.ModelType]) data, err := modelSvc.GetById(id) if err != nil { return HandleError(err) } return HandleSuccessWithData(data) } func (svr ModelBaseServiceServerV2) GetOne(_ context.Context, req *grpc.ModelServiceV2GetOneRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } var options mongo.FindOptions err = json.Unmarshal(req.FindOptions, &options) if err != nil { return HandleError(err) } modelSvc := service.NewModelServiceV2WithColName[bson.M](typeNameColNameMap[req.ModelType]) data, err := modelSvc.GetOne(query, &options) if err != nil { return HandleError(err) } return HandleSuccessWithData(data) } func (svr ModelBaseServiceServerV2) GetMany(_ context.Context, req *grpc.ModelServiceV2GetManyRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } var options mongo.FindOptions err = json.Unmarshal(req.FindOptions, &options) if err != nil { return HandleError(err) } modelSvc := service.NewModelServiceV2WithColName[bson.M](typeNameColNameMap[req.ModelType]) data, err := modelSvc.GetMany(query, &options) if err != nil { return HandleError(err) } return HandleSuccessWithData(data) } func (svr ModelBaseServiceServerV2) DeleteById(_ context.Context, req *grpc.ModelServiceV2DeleteByIdRequest) (res *grpc.Response, err error) { id, err := primitive.ObjectIDFromHex(req.Id) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.DeleteById(id) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) DeleteOne(_ context.Context, req *grpc.ModelServiceV2DeleteOneRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.DeleteOne(query) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) DeleteMany(_ context.Context, req *grpc.ModelServiceV2DeleteManyRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.DeleteMany(query) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) UpdateById(_ context.Context, req *grpc.ModelServiceV2UpdateByIdRequest) (res *grpc.Response, err error) { id, err := primitive.ObjectIDFromHex(req.Id) if err != nil { return HandleError(err) } var update bson.M err = json.Unmarshal(req.Update, &update) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.UpdateById(id, update) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) UpdateOne(_ context.Context, req *grpc.ModelServiceV2UpdateOneRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } var update bson.M err = json.Unmarshal(req.Update, &update) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.UpdateOne(query, update) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) UpdateMany(_ context.Context, req *grpc.ModelServiceV2UpdateManyRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } var update bson.M err = json.Unmarshal(req.Update, &update) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.UpdateMany(query, update) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) ReplaceById(_ context.Context, req *grpc.ModelServiceV2ReplaceByIdRequest) (res *grpc.Response, err error) { id, err := primitive.ObjectIDFromHex(req.Id) if err != nil { return HandleError(err) } model := GetOneInstanceModel(req.ModelType) modelType := reflect.TypeOf(model) modelValuePtr := reflect.New(modelType).Interface() err = json.Unmarshal(req.Model, modelValuePtr) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.GetCol().ReplaceId(id, modelValuePtr) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) ReplaceOne(_ context.Context, req *grpc.ModelServiceV2ReplaceOneRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } model := GetOneInstanceModel(req.ModelType) modelType := reflect.TypeOf(model) modelValuePtr := reflect.New(modelType).Interface() err = json.Unmarshal(req.Model, &modelValuePtr) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) err = modelSvc.GetCol().Replace(query, modelValuePtr) if err != nil { return HandleError(err) } return HandleSuccess() } func (svr ModelBaseServiceServerV2) InsertOne(_ context.Context, req *grpc.ModelServiceV2InsertOneRequest) (res *grpc.Response, err error) { model := GetOneInstanceModel(req.ModelType) modelType := reflect.TypeOf(model) modelValuePtr := reflect.New(modelType).Interface() err = json.Unmarshal(req.Model, modelValuePtr) if err != nil { return HandleError(err) } modelSvc := GetModelService[bson.M](req.ModelType) r, err := modelSvc.GetCol().GetCollection().InsertOne(modelSvc.GetCol().GetContext(), modelValuePtr) if err != nil { return HandleError(err) } return HandleSuccessWithData(r.InsertedID) } func (svr ModelBaseServiceServerV2) InsertMany(_ context.Context, req *grpc.ModelServiceV2InsertManyRequest) (res *grpc.Response, err error) { model := GetOneInstanceModel(req.ModelType) modelType := reflect.TypeOf(model) modelsSliceType := reflect.SliceOf(modelType) modelsSlicePtr := reflect.New(modelsSliceType).Interface() err = json.Unmarshal(req.Models, modelsSlicePtr) if err != nil { return HandleError(err) } modelsSlice := reflect.ValueOf(modelsSlicePtr).Elem() modelsInterface := make([]any, modelsSlice.Len()) for i := 0; i < modelsSlice.Len(); i++ { modelsInterface[i] = modelsSlice.Index(i).Interface() } modelSvc := GetModelService[bson.M](req.ModelType) r, err := modelSvc.GetCol().GetCollection().InsertMany(modelSvc.GetCol().GetContext(), modelsInterface) if err != nil { return HandleError(err) } return HandleSuccessWithData(r.InsertedIDs) } func (svr ModelBaseServiceServerV2) Count(_ context.Context, req *grpc.ModelServiceV2CountRequest) (res *grpc.Response, err error) { var query bson.M err = json.Unmarshal(req.Query, &query) if err != nil { return HandleError(err) } count, err := GetModelService[bson.M](req.ModelType).Count(query) if err != nil { return HandleError(err) } return HandleSuccessWithData(count) } func GetModelService[T any](typeName string) *service.ModelServiceV2[T] { return service.NewModelServiceV2WithColName[T](typeNameColNameMap[typeName]) } func NewModelBaseServiceV2Server() *ModelBaseServiceServerV2 { return &ModelBaseServiceServerV2{} } ================================================ FILE: core/grpc/server/model_delegate_binder.go ================================================ package server import ( "encoding/json" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/grpc" ) func NewModelDelegateBinder(req *grpc.Request) (b *ModelDelegateBinder) { return &ModelDelegateBinder{ req: req, msg: &entity.GrpcDelegateMessage{}, } } type ModelDelegateBinder struct { req *grpc.Request msg interfaces.GrpcModelDelegateMessage } func (b *ModelDelegateBinder) Bind() (res interface{}, err error) { if err := b.bindDelegateMessage(); err != nil { return nil, err } m := models.NewModelMap() switch b.msg.GetModelId() { case interfaces.ModelIdArtifact: return b.process(&m.Artifact, interfaces.ModelIdTag) case interfaces.ModelIdTag: return b.process(&m.Tag, interfaces.ModelIdTag) case interfaces.ModelIdNode: return b.process(&m.Node, interfaces.ModelIdTag) case interfaces.ModelIdProject: return b.process(&m.Project, interfaces.ModelIdTag) case interfaces.ModelIdSpider: return b.process(&m.Spider, interfaces.ModelIdTag) case interfaces.ModelIdTask: return b.process(&m.Task) case interfaces.ModelIdJob: return b.process(&m.Job) case interfaces.ModelIdSchedule: return b.process(&m.Schedule) case interfaces.ModelIdUser: return b.process(&m.User) case interfaces.ModelIdSetting: return b.process(&m.Setting) case interfaces.ModelIdToken: return b.process(&m.Token) case interfaces.ModelIdVariable: return b.process(&m.Variable) case interfaces.ModelIdTaskQueue: return b.process(&m.TaskQueueItem) case interfaces.ModelIdTaskStat: return b.process(&m.TaskStat) case interfaces.ModelIdSpiderStat: return b.process(&m.SpiderStat) case interfaces.ModelIdDataSource: return b.process(&m.DataSource) case interfaces.ModelIdDataCollection: return b.process(&m.DataCollection) case interfaces.ModelIdResult: return b.process(&m.Result) case interfaces.ModelIdPassword: return b.process(&m.Password) case interfaces.ModelIdExtraValue: return b.process(&m.ExtraValue) case interfaces.ModelIdGit: return b.process(&m.Git) case interfaces.ModelIdRole: return b.process(&m.Role) case interfaces.ModelIdUserRole: return b.process(&m.UserRole) case interfaces.ModelIdPermission: return b.process(&m.Permission) case interfaces.ModelIdRolePermission: return b.process(&m.RolePermission) case interfaces.ModelIdEnvironment: return b.process(&m.Environment) case interfaces.ModelIdDependencySetting: return b.process(&m.DependencySetting) default: return nil, errors.ErrorModelInvalidModelId } } func (b *ModelDelegateBinder) MustBind() (res interface{}) { res, err := b.Bind() if err != nil { panic(err) } return res } func (b *ModelDelegateBinder) BindWithDelegateMessage() (res interface{}, msg interfaces.GrpcModelDelegateMessage, err error) { if err := json.Unmarshal(b.req.Data, b.msg); err != nil { return nil, nil, err } res, err = b.Bind() if err != nil { return nil, nil, err } return res, b.msg, nil } func (b *ModelDelegateBinder) process(d interface{}, fieldIds ...interfaces.ModelId) (res interface{}, err error) { if err := json.Unmarshal(b.msg.GetData(), d); err != nil { return nil, err } //return models.AssignFields(d, fieldIds...) // TODO: do we need to assign fields? return d, nil } func (b *ModelDelegateBinder) bindDelegateMessage() (err error) { return json.Unmarshal(b.req.Data, b.msg) } ================================================ FILE: core/grpc/server/model_delegate_server.go ================================================ package server import ( "context" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" grpc "github.com/crawlab-team/crawlab/grpc" ) type ModelDelegateServer struct { grpc.UnimplementedModelDelegateServer } // Do and perform an RPC action of constants.Delegate func (svr ModelDelegateServer) Do(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { // bind message obj, msg, err := NewModelDelegateBinder(req).BindWithDelegateMessage() if err != nil { return HandleError(err) } // convert to model doc, ok := obj.(interfaces.Model) if !ok { return HandleError(errors.ErrorModelInvalidType) } // model delegate d := delegate.NewModelDelegate(doc) // apply method switch msg.GetMethod() { case interfaces.ModelDelegateMethodAdd: err = d.Add() case interfaces.ModelDelegateMethodSave: err = d.Save() case interfaces.ModelDelegateMethodDelete: err = d.Delete() case interfaces.ModelDelegateMethodGetArtifact, interfaces.ModelDelegateMethodRefresh: err = d.Refresh() } if err != nil { return HandleError(err) } // model m := d.GetModel() if msg.GetMethod() == interfaces.ModelDelegateMethodGetArtifact { m, err = d.GetArtifact() if err != nil { return nil, err } } // json bytes data, err := d.ToBytes(m) if err != nil { return nil, err } return HandleSuccessWithData(data) } func NewModelDelegateServer() (svr *ModelDelegateServer) { return &ModelDelegateServer{} } ================================================ FILE: core/grpc/server/node_server.go ================================================ package server import ( "context" "encoding/json" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/grpc" "go.mongodb.org/mongo-driver/mongo" ) type NodeServer struct { grpc.UnimplementedNodeServiceServer // dependencies modelSvc service.ModelService cfgSvc interfaces.NodeConfigService // internals server interfaces.GrpcServer } // Register from handler/worker to master func (svr NodeServer) Register(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { // unmarshall data var nodeInfo entity.NodeInfo if req.Data != nil { if err := json.Unmarshal(req.Data, &nodeInfo); err != nil { return HandleError(err) } if nodeInfo.IsMaster { // error: cannot register master node return HandleError(errors.ErrorGrpcNotAllowed) } } // node key var nodeKey string if req.NodeKey != "" { nodeKey = req.NodeKey } else { nodeKey = nodeInfo.Key } if nodeKey == "" { return HandleError(errors.ErrorModelMissingRequiredData) } // find in db node, err := svr.modelSvc.GetNodeByKey(nodeKey, nil) if err == nil { if node.IsMaster { // error: cannot register master node return HandleError(errors.ErrorGrpcNotAllowed) } else { // register existing node.Status = constants.NodeStatusRegistered node.Active = true nodeD := delegate.NewModelNodeDelegate(node) if err := nodeD.Save(); err != nil { return HandleError(err) } var ok bool node, ok = nodeD.GetModel().(*models.Node) if !ok { return HandleError(errors.ErrorGrpcInvalidType) } log.Infof("[NodeServer] updated worker[%s] in db. id: %s", nodeKey, nodeD.GetModel().GetId().Hex()) } } else if err == mongo.ErrNoDocuments { // register new node = &models.Node{ Key: nodeKey, Name: nodeInfo.Name, Ip: nodeInfo.Ip, Hostname: nodeInfo.Hostname, Description: nodeInfo.Description, MaxRunners: nodeInfo.MaxRunners, Status: constants.NodeStatusRegistered, Active: true, Enabled: true, } if node.Name == "" { node.Name = nodeKey } nodeD := delegate.NewModelDelegate(node) if err := nodeD.Add(); err != nil { return HandleError(err) } var ok bool node, ok = nodeD.GetModel().(*models.Node) if !ok { return HandleError(errors.ErrorGrpcInvalidType) } log.Infof("[NodeServer] added worker[%s] in db. id: %s", nodeKey, nodeD.GetModel().GetId().Hex()) } else { // error return HandleError(err) } log.Infof("[NodeServer] master registered worker[%s]", req.GetNodeKey()) return HandleSuccessWithData(node) } // SendHeartbeat from worker to master func (svr NodeServer) SendHeartbeat(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { // find in db node, err := svr.modelSvc.GetNodeByKey(req.NodeKey, nil) if err != nil { if err == mongo.ErrNoDocuments { return HandleError(errors.ErrorNodeNotExists) } return HandleError(err) } // validate status if node.Status == constants.NodeStatusUnregistered { return HandleError(errors.ErrorNodeUnregistered) } // update status nodeD := delegate.NewModelNodeDelegate(node) if err := nodeD.UpdateStatusOnline(); err != nil { return HandleError(err) } return HandleSuccessWithData(node) } // Ping from worker to master func (svr NodeServer) Ping(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { return HandleSuccess() } func (svr NodeServer) Subscribe(request *grpc.Request, stream grpc.NodeService_SubscribeServer) (err error) { log.Infof("[NodeServer] master received subscribe request from node[%s]", request.NodeKey) // finished channel finished := make(chan bool) // set subscribe svr.server.SetSubscribe("node:"+request.NodeKey, &entity.GrpcSubscribe{ Stream: stream, Finished: finished, }) ctx := stream.Context() log.Infof("[NodeServer] master subscribed node[%s]", request.NodeKey) // Keep this scope alive because once this scope exits - the stream is closed for { select { case <-finished: log.Infof("[NodeServer] closing stream for node[%s]", request.NodeKey) return nil case <-ctx.Done(): log.Infof("[NodeServer] node[%s] has disconnected", request.NodeKey) return nil } } } func (svr NodeServer) Unsubscribe(ctx context.Context, req *grpc.Request) (res *grpc.Response, err error) { sub, err := svr.server.GetSubscribe("node:" + req.NodeKey) if err != nil { return nil, errors.ErrorGrpcSubscribeNotExists } select { case sub.GetFinished() <- true: log.Infof("unsubscribed node[%s]", req.NodeKey) default: // Default case is to avoid blocking in case client has already unsubscribed } svr.server.DeleteSubscribe(req.NodeKey) return &grpc.Response{ Code: grpc.ResponseCode_OK, Message: "unsubscribed successfully", }, nil } func NewNodeServer() (res *NodeServer, err error) { // node server svr := &NodeServer{} svr.modelSvc, err = service.GetService() if err != nil { return nil, err } svr.cfgSvc = nodeconfig.GetNodeConfigService() return svr, nil } ================================================ FILE: core/grpc/server/node_server_v2.go ================================================ package server import ( "context" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/notification" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/grpc" errors2 "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "sync" "time" ) type NodeServerV2 struct { grpc.UnimplementedNodeServiceServer // dependencies cfgSvc interfaces.NodeConfigService // internals server *GrpcServerV2 } // Register from handler/worker to master func (svr NodeServerV2) Register(_ context.Context, req *grpc.NodeServiceRegisterRequest) (res *grpc.Response, err error) { // unmarshall data if req.IsMaster { // error: cannot register master node return HandleError(errors.ErrorGrpcNotAllowed) } // node key if req.Key == "" { return HandleError(errors.ErrorModelMissingRequiredData) } // find in db var node *models.NodeV2 node, err = service.NewModelServiceV2[models.NodeV2]().GetOne(bson.M{"key": req.Key}, nil) if err == nil { // register existing node.Status = constants.NodeStatusRegistered node.Active = true node.ActiveAt = time.Now() err = service.NewModelServiceV2[models.NodeV2]().ReplaceById(node.Id, *node) if err != nil { return HandleError(err) } log.Infof("[NodeServerV2] updated worker[%s] in db. id: %s", req.Key, node.Id.Hex()) } else if errors2.Is(err, mongo.ErrNoDocuments) { // register new node = &models.NodeV2{ Key: req.Key, Name: req.Name, Status: constants.NodeStatusRegistered, Active: true, ActiveAt: time.Now(), Enabled: true, MaxRunners: int(req.MaxRunners), } node.SetCreated(primitive.NilObjectID) node.SetUpdated(primitive.NilObjectID) node.Id, err = service.NewModelServiceV2[models.NodeV2]().InsertOne(*node) if err != nil { return HandleError(err) } log.Infof("[NodeServerV2] added worker[%s] in db. id: %s", req.Key, node.Id.Hex()) } else { // error return HandleError(err) } log.Infof("[NodeServerV2] master registered worker[%s]", req.Key) return HandleSuccessWithData(node) } // SendHeartbeat from worker to master func (svr NodeServerV2) SendHeartbeat(_ context.Context, req *grpc.NodeServiceSendHeartbeatRequest) (res *grpc.Response, err error) { // find in db node, err := service.NewModelServiceV2[models.NodeV2]().GetOne(bson.M{"key": req.Key}, nil) if err != nil { if errors2.Is(err, mongo.ErrNoDocuments) { return HandleError(errors.ErrorNodeNotExists) } return HandleError(err) } oldStatus := node.Status // validate status if node.Status == constants.NodeStatusUnregistered { return HandleError(errors.ErrorNodeUnregistered) } // update status node.Status = constants.NodeStatusOnline node.Active = true node.ActiveAt = time.Now() err = service.NewModelServiceV2[models.NodeV2]().ReplaceById(node.Id, *node) if err != nil { return HandleError(err) } newStatus := node.Status // send notification if status changed if utils.IsPro() { if oldStatus != newStatus { go notification.GetNotificationServiceV2().SendNodeNotification(node) } } return HandleSuccessWithData(node) } func (svr NodeServerV2) Subscribe(request *grpc.Request, stream grpc.NodeService_SubscribeServer) (err error) { log.Infof("[NodeServerV2] master received subscribe request from node[%s]", request.NodeKey) // finished channel finished := make(chan bool) // set subscribe svr.server.SetSubscribe("node:"+request.NodeKey, &entity.GrpcSubscribe{ Stream: stream, Finished: finished, }) ctx := stream.Context() log.Infof("[NodeServerV2] master subscribed node[%s]", request.NodeKey) // Keep this scope alive because once this scope exits - the stream is closed for { select { case <-finished: log.Infof("[NodeServerV2] closing stream for node[%s]", request.NodeKey) return nil case <-ctx.Done(): log.Infof("[NodeServerV2] node[%s] has disconnected", request.NodeKey) return nil } } } func (svr NodeServerV2) Unsubscribe(_ context.Context, req *grpc.Request) (res *grpc.Response, err error) { sub, err := svr.server.GetSubscribe("node:" + req.NodeKey) if err != nil { return nil, errors.ErrorGrpcSubscribeNotExists } select { case sub.GetFinished() <- true: log.Infof("unsubscribed node[%s]", req.NodeKey) default: // Default case is to avoid blocking in case client has already unsubscribed } svr.server.DeleteSubscribe(req.NodeKey) return &grpc.Response{ Code: grpc.ResponseCode_OK, Message: "unsubscribed successfully", }, nil } var nodeSvrV2 *NodeServerV2 var nodeSvrV2Once = new(sync.Once) func NewNodeServerV2() (res *NodeServerV2, err error) { if nodeSvrV2 != nil { return nodeSvrV2, nil } nodeSvrV2Once.Do(func() { nodeSvrV2 = &NodeServerV2{} nodeSvrV2.cfgSvc = nodeconfig.GetNodeConfigService() if err != nil { log.Errorf("[NodeServerV2] error: %s", err.Error()) } }) if err != nil { return nil, err } return nodeSvrV2, nil } ================================================ FILE: core/grpc/server/server_v2.go ================================================ package server import ( "encoding/json" "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/grpc/middlewares" "github.com/crawlab-team/crawlab/core/interfaces" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" grpc2 "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" errors2 "github.com/pkg/errors" "github.com/spf13/viper" "go/types" "google.golang.org/grpc" "net" "sync" ) var ( subsV2 = map[string]interfaces.GrpcSubscribe{} mutexSubsV2 = &sync.Mutex{} ) type GrpcServerV2 struct { // settings cfgPath string address interfaces.Address // internals svr *grpc.Server l net.Listener stopped bool // dependencies nodeCfgSvc interfaces.NodeConfigService // servers NodeSvr *NodeServerV2 TaskSvr *TaskServerV2 ModelBaseServiceSvr *ModelBaseServiceServerV2 DependenciesSvr *DependenciesServerV2 MetricsSvr *MetricsServerV2 } func (svr *GrpcServerV2) GetConfigPath() (path string) { return svr.cfgPath } func (svr *GrpcServerV2) SetConfigPath(path string) { svr.cfgPath = path } func (svr *GrpcServerV2) Init() (err error) { // register if err := svr.Register(); err != nil { return err } return nil } func (svr *GrpcServerV2) Start() (err error) { // grpc server binding address address := svr.address.String() // listener svr.l, err = net.Listen("tcp", address) if err != nil { _ = trace.TraceError(err) return errors.ErrorGrpcServerFailedToListen } log.Infof("grpc server listens to %s", address) // start grpc server go func() { if err := svr.svr.Serve(svr.l); err != nil { if errors2.Is(err, grpc.ErrServerStopped) { return } trace.PrintError(err) log.Error(errors.ErrorGrpcServerFailedToServe.Error()) } }() return nil } func (svr *GrpcServerV2) Stop() (err error) { // skip if listener is nil if svr.l == nil { return nil } // graceful stop log.Infof("grpc server stopping...") svr.svr.Stop() // close listener log.Infof("grpc server closing listener...") _ = svr.l.Close() // mark as stopped svr.stopped = true // log log.Infof("grpc server stopped") return nil } func (svr *GrpcServerV2) Register() (err error) { grpc2.RegisterNodeServiceServer(svr.svr, *svr.NodeSvr) grpc2.RegisterModelBaseServiceV2Server(svr.svr, *svr.ModelBaseServiceSvr) grpc2.RegisterTaskServiceServer(svr.svr, *svr.TaskSvr) grpc2.RegisterDependenciesServiceV2Server(svr.svr, *svr.DependenciesSvr) grpc2.RegisterMetricsServiceV2Server(svr.svr, *svr.MetricsSvr) return nil } func (svr *GrpcServerV2) recoveryHandlerFunc(p interface{}) (err error) { err = errors.NewError(errors.ErrorPrefixGrpc, fmt.Sprintf("%v", p)) trace.PrintError(err) return err } func (svr *GrpcServerV2) SetAddress(address interfaces.Address) { } func (svr *GrpcServerV2) GetSubscribe(key string) (sub interfaces.GrpcSubscribe, err error) { mutexSubsV2.Lock() defer mutexSubsV2.Unlock() sub, ok := subsV2[key] if !ok { return nil, errors.ErrorGrpcSubscribeNotExists } return sub, nil } func (svr *GrpcServerV2) SetSubscribe(key string, sub interfaces.GrpcSubscribe) { mutexSubsV2.Lock() defer mutexSubsV2.Unlock() subsV2[key] = sub } func (svr *GrpcServerV2) DeleteSubscribe(key string) { mutexSubsV2.Lock() defer mutexSubsV2.Unlock() delete(subsV2, key) } func (svr *GrpcServerV2) SendStreamMessage(key string, code grpc2.StreamMessageCode) (err error) { return svr.SendStreamMessageWithData(key, code, nil) } func (svr *GrpcServerV2) SendStreamMessageWithData(key string, code grpc2.StreamMessageCode, d interface{}) (err error) { var data []byte switch d.(type) { case types.Nil: // do nothing case []byte: data = d.([]byte) default: var err error data, err = json.Marshal(d) if err != nil { return err } } sub, err := svr.GetSubscribe(key) if err != nil { return err } msg := &grpc2.StreamMessage{ Code: code, Key: svr.nodeCfgSvc.GetNodeKey(), Data: data, } return sub.GetStream().Send(msg) } func (svr *GrpcServerV2) IsStopped() (res bool) { return svr.stopped } func NewGrpcServerV2() (svr *GrpcServerV2, err error) { // server svr = &GrpcServerV2{ address: entity.NewAddress(&entity.AddressOptions{ Host: constants.DefaultGrpcServerHost, Port: constants.DefaultGrpcServerPort, }), } if viper.GetString("grpc.server.address") != "" { svr.address, err = entity.NewAddressFromString(viper.GetString("grpc.server.address")) if err != nil { return nil, err } } svr.nodeCfgSvc = nodeconfig.GetNodeConfigService() svr.NodeSvr, err = NewNodeServerV2() if err != nil { return nil, err } svr.ModelBaseServiceSvr = NewModelBaseServiceV2Server() svr.TaskSvr, err = NewTaskServerV2() if err != nil { return nil, err } svr.DependenciesSvr = GetDependenciesServerV2() svr.MetricsSvr = GetMetricsServerV2() // recovery options recoveryOpts := []grpc_recovery.Option{ grpc_recovery.WithRecoveryHandler(svr.recoveryHandlerFunc), } // grpc server svr.svr = grpc.NewServer( grpc_middleware.WithUnaryServerChain( grpc_recovery.UnaryServerInterceptor(recoveryOpts...), grpc_auth.UnaryServerInterceptor(middlewares.GetAuthTokenFunc(svr.nodeCfgSvc)), ), grpc_middleware.WithStreamServerChain( grpc_recovery.StreamServerInterceptor(recoveryOpts...), grpc_auth.StreamServerInterceptor(middlewares.GetAuthTokenFunc(svr.nodeCfgSvc)), ), ) // initialize if err := svr.Init(); err != nil { return nil, err } return svr, nil } var _serverV2 *GrpcServerV2 func GetGrpcServerV2() (svr *GrpcServerV2, err error) { if _serverV2 != nil { return _serverV2, nil } _serverV2, err = NewGrpcServerV2() if err != nil { return nil, err } return _serverV2, nil } ================================================ FILE: core/grpc/server/task_server_v2.go ================================================ package server import ( "context" "encoding/json" "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/notification" "github.com/crawlab-team/crawlab/core/task/stats" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "io" "strings" ) type TaskServerV2 struct { grpc.UnimplementedTaskServiceServer // dependencies cfgSvc interfaces.NodeConfigService statsSvc *stats.ServiceV2 // internals server interfaces.GrpcServer } // Subscribe to task stream when a task runner in a node starts func (svr TaskServerV2) Subscribe(stream grpc.TaskService_SubscribeServer) (err error) { for { msg, err := stream.Recv() utils.LogDebug(msg.String()) if err == io.EOF { return nil } if err != nil { if strings.HasSuffix(err.Error(), "context canceled") { return nil } trace.PrintError(err) continue } switch msg.Code { case grpc.StreamMessageCode_INSERT_DATA: err = svr.handleInsertData(msg) case grpc.StreamMessageCode_INSERT_LOGS: err = svr.handleInsertLogs(msg) default: err = errors.New("invalid stream message code") log.Errorf("invalid stream message code: %d", msg.Code) continue } if err != nil { log.Errorf("grpc error[%d]: %v", msg.Code, err) } } } // Fetch tasks to be executed by a task handler func (svr TaskServerV2) Fetch(ctx context.Context, request *grpc.Request) (response *grpc.Response, err error) { nodeKey := request.GetNodeKey() if nodeKey == "" { return nil, errors.New("invalid node key") } n, err := service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": nodeKey}, nil) if err != nil { return nil, trace.TraceError(err) } var tid primitive.ObjectID opts := &mongo.FindOptions{ Sort: bson.D{ {"p", 1}, {"_id", 1}, }, Limit: 1, } if err := mongo.RunTransactionWithContext(ctx, func(sc mongo2.SessionContext) (err error) { // get task queue item assigned to this node tid, err = svr.getTaskQueueItemIdAndDequeue(bson.M{"nid": n.Id}, opts, n.Id) if err != nil { return err } if !tid.IsZero() { return nil } // get task queue item assigned to any node (random mode) tid, err = svr.getTaskQueueItemIdAndDequeue(bson.M{"nid": nil}, opts, n.Id) if !tid.IsZero() { return nil } if err != nil { return err } return nil }); err != nil { return nil, err } return HandleSuccessWithData(tid) } func (svr TaskServerV2) SendNotification(_ context.Context, request *grpc.TaskServiceSendNotificationRequest) (response *grpc.Response, err error) { if !utils.IsPro() { return nil, nil } // task id taskId, err := primitive.ObjectIDFromHex(request.TaskId) if err != nil { log.Errorf("invalid task id: %s", request.TaskId) return nil, trace.TraceError(err) } // arguments var args []any // task task, err := service.NewModelServiceV2[models2.TaskV2]().GetById(taskId) if err != nil { log.Errorf("task not found: %s", request.TaskId) return nil, trace.TraceError(err) } args = append(args, task) // task stat taskStat, err := service.NewModelServiceV2[models2.TaskStatV2]().GetById(task.Id) if err != nil { log.Errorf("task stat not found for task: %s", request.TaskId) return nil, trace.TraceError(err) } args = append(args, taskStat) // spider spider, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(task.SpiderId) if err != nil { log.Errorf("spider not found for task: %s", request.TaskId) return nil, trace.TraceError(err) } args = append(args, spider) // node node, err := service.NewModelServiceV2[models2.NodeV2]().GetById(task.NodeId) if err != nil { return nil, trace.TraceError(err) } args = append(args, node) // schedule var schedule *models2.ScheduleV2 if !task.ScheduleId.IsZero() { schedule, err = service.NewModelServiceV2[models2.ScheduleV2]().GetById(task.ScheduleId) if err != nil { log.Errorf("schedule not found for task: %s", request.TaskId) return nil, trace.TraceError(err) } args = append(args, schedule) } // settings settings, err := service.NewModelServiceV2[models2.NotificationSettingV2]().GetMany(bson.M{ "enabled": true, "trigger": bson.M{ "$regex": constants.NotificationTriggerPatternTask, }, }, nil) if err != nil { return nil, trace.TraceError(err) } // notification service svc := notification.GetNotificationServiceV2() for _, s := range settings { // compatible with old settings trigger := s.Trigger if trigger == "" { trigger = s.TaskTrigger } // send notification switch trigger { case constants.NotificationTriggerTaskFinish: if task.Status != constants.TaskStatusPending && task.Status != constants.TaskStatusRunning { go svc.Send(&s, args...) } case constants.NotificationTriggerTaskError: if task.Status == constants.TaskStatusError || task.Status == constants.TaskStatusAbnormal { go svc.Send(&s, args...) } case constants.NotificationTriggerTaskEmptyResults: if task.Status != constants.TaskStatusPending && task.Status != constants.TaskStatusRunning { if taskStat.ResultCount == 0 { go svc.Send(&s, args...) } } } } return nil, nil } func (svr TaskServerV2) handleInsertData(msg *grpc.StreamMessage) (err error) { data, err := svr.deserialize(msg) if err != nil { return err } var records []map[string]interface{} for _, d := range data.Records { res, ok := d[constants.TaskKey] if ok { switch res.(type) { case string: id, err := primitive.ObjectIDFromHex(res.(string)) if err == nil { d[constants.TaskKey] = id } } } records = append(records, d) } return svr.statsSvc.InsertData(data.TaskId, records...) } func (svr TaskServerV2) handleInsertLogs(msg *grpc.StreamMessage) (err error) { data, err := svr.deserialize(msg) if err != nil { return err } return svr.statsSvc.InsertLogs(data.TaskId, data.Logs...) } func (svr TaskServerV2) getTaskQueueItemIdAndDequeue(query bson.M, opts *mongo.FindOptions, nid primitive.ObjectID) (tid primitive.ObjectID, err error) { tq, err := service.NewModelServiceV2[models2.TaskQueueItemV2]().GetOne(query, opts) if err != nil { if errors.Is(err, mongo2.ErrNoDocuments) { return tid, nil } return tid, trace.TraceError(err) } t, err := service.NewModelServiceV2[models2.TaskV2]().GetById(tq.Id) if err == nil { t.NodeId = nid err = service.NewModelServiceV2[models2.TaskV2]().ReplaceById(t.Id, *t) if err != nil { return tid, trace.TraceError(err) } } err = service.NewModelServiceV2[models2.TaskQueueItemV2]().DeleteById(tq.Id) if err != nil { return tid, trace.TraceError(err) } return tq.Id, nil } func (svr TaskServerV2) deserialize(msg *grpc.StreamMessage) (data entity.StreamMessageTaskData, err error) { if err := json.Unmarshal(msg.Data, &data); err != nil { return data, trace.TraceError(err) } if data.TaskId.IsZero() { return data, errors.New("invalid task id") } return data, nil } func NewTaskServerV2() (res *TaskServerV2, err error) { // task server svr := &TaskServerV2{} svr.cfgSvc = nodeconfig.GetNodeConfigService() svr.statsSvc, err = stats.GetTaskStatsServiceV2() if err != nil { return nil, err } return svr, nil } ================================================ FILE: core/grpc/server/utils_handle.go ================================================ package server import ( "encoding/json" "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" ) func HandleError(err error) (res *grpc.Response, err2 error) { trace.PrintError(err) return &grpc.Response{ Code: grpc.ResponseCode_ERROR, Error: err.Error(), }, err } func HandleSuccess() (res *grpc.Response, err error) { return &grpc.Response{ Code: grpc.ResponseCode_OK, Message: "success", }, nil } func HandleSuccessWithData(data interface{}) (res *grpc.Response, err error) { var bytes []byte switch data.(type) { case []byte: bytes = data.([]byte) default: bytes, err = json.Marshal(data) if err != nil { return HandleError(err) } } return &grpc.Response{ Code: grpc.ResponseCode_OK, Message: "success", Data: bytes, }, nil } func HandleSuccessWithListData(data interface{}, total int) (res *grpc.Response, err error) { bytes, err := json.Marshal(data) if err != nil { return HandleError(err) } return &grpc.Response{ Code: grpc.ResponseCode_OK, Message: "success", Data: bytes, Total: int64(total), }, nil } ================================================ FILE: core/i18n/service.go ================================================ package i18n import "github.com/crawlab-team/crawlab/core/interfaces" var translations []interfaces.Translation var _svc interfaces.I18nService type Service struct { } func (svc *Service) AddTranslations(t []interfaces.Translation) { translations = append(translations, t...) } func (svc *Service) GetTranslations() (t []interfaces.Translation) { return translations } func GetI18nService(cfgPath string) (svc2 interfaces.I18nService, err error) { if _svc != nil { return _svc, nil } _svc, err = NewI18nService() if err != nil { return nil, err } return _svc, nil } func ProvideGetI18nService(cfgPath string) func() (svc interfaces.I18nService, err error) { return func() (svc interfaces.I18nService, err error) { return GetI18nService(cfgPath) } } func NewI18nService() (svc2 interfaces.I18nService, err error) { svc := &Service{} return svc, nil } ================================================ FILE: core/interfaces/address.go ================================================ package interfaces type Address interface { Entity String() string IsEmpty() bool } ================================================ FILE: core/interfaces/color.go ================================================ package interfaces type Color interface { Entity GetHex() string GetName() string } ================================================ FILE: core/interfaces/color_service.go ================================================ package interfaces type ColorService interface { Injectable GetByName(name string) (res Color, err error) GetRandom() (res Color, err error) } ================================================ FILE: core/interfaces/controller_params.go ================================================ package interfaces type ControllerParams interface { IsZero() (ok bool) IsDefault() (ok bool) } ================================================ FILE: core/interfaces/data_source_service.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type DataSourceService interface { ChangePassword(id primitive.ObjectID, password string) (err error) Monitor() CheckStatus(id primitive.ObjectID) (err error) SetTimeout(duration time.Duration) SetMonitorInterval(duration time.Duration) } ================================================ FILE: core/interfaces/entity.go ================================================ package interfaces type Entity interface { Value() interface{} } ================================================ FILE: core/interfaces/event_data.go ================================================ package interfaces type EventData interface { GetEvent() string GetData() interface{} } ================================================ FILE: core/interfaces/event_service.go ================================================ package interfaces type EventFn func(data ...interface{}) (err error) type EventService interface { Register(key, include, exclude string, ch *chan EventData) Unregister(key string) SendEvent(eventName string, data ...interface{}) } ================================================ FILE: core/interfaces/export.go ================================================ package interfaces import "time" type Export interface { GetId() string GetType() string GetTarget() string GetFilter() Filter GetStatus() string GetStartTs() time.Time GetEndTs() time.Time GetDownloadPath() string } ================================================ FILE: core/interfaces/export_service.go ================================================ package interfaces type ExportService interface { GenerateId() (exportId string, err error) Export(exportType, target string, filter Filter) (exportId string, err error) GetExport(exportId string) (export Export, err error) } ================================================ FILE: core/interfaces/filter.go ================================================ package interfaces type Filter interface { GetIsOr() (isOr bool) SetIsOr(isOr bool) GetConditions() (conditions []FilterCondition) SetConditions(conditions []FilterCondition) IsNil() (ok bool) } ================================================ FILE: core/interfaces/filter_condition.go ================================================ package interfaces type FilterCondition interface { GetKey() (key string) SetKey(key string) GetOp() (op string) SetOp(op string) GetValue() (value interface{}) SetValue(value interface{}) } ================================================ FILE: core/interfaces/fs_file_info.go ================================================ package interfaces import ( "os" "time" ) type FsFileInfo interface { GetName() string GetPath() string GetFullPath() string GetExtension() string GetIsDir() bool GetFileSize() int64 GetModTime() time.Time GetMode() os.FileMode GetHash() string GetChildren() []FsFileInfo } ================================================ FILE: core/interfaces/fs_service.go ================================================ package interfaces import ( cfs "github.com/crawlab-team/crawlab/fs" vcs "github.com/crawlab-team/crawlab/vcs" ) type FsService interface { WithConfigPath List(path string, opts ...ServiceCrudOption) (files []FsFileInfo, err error) GetFile(path string, opts ...ServiceCrudOption) (data []byte, err error) GetFileInfo(path string, opts ...ServiceCrudOption) (file FsFileInfo, err error) Save(path string, data []byte, opts ...ServiceCrudOption) (err error) Rename(path, newPath string, opts ...ServiceCrudOption) (err error) Delete(path string, opts ...ServiceCrudOption) (err error) Copy(path, newPath string, opts ...ServiceCrudOption) (err error) Commit(msg string) (err error) SyncToFs(opts ...ServiceCrudOption) (err error) SyncToWorkspace() (err error) GetFsPath() (path string) SetFsPath(path string) GetWorkspacePath() (path string) SetWorkspacePath(path string) GetRepoPath() (path string) SetRepoPath(path string) GetFs() (fs cfs.Manager) GetGitClient() (c *vcs.GitClient) } ================================================ FILE: core/interfaces/fs_service_options.go ================================================ package interfaces type ServiceCrudOptions struct { IsAbsolute bool // whether the path is absolute OnlyFromWorkspace bool // whether only sync from workspace NotSyncToWorkspace bool // whether not sync to workspace } type ServiceCrudOption func(o *ServiceCrudOptions) func WithOnlyFromWorkspace() ServiceCrudOption { return func(o *ServiceCrudOptions) { o.OnlyFromWorkspace = true } } func WithNotSyncToWorkspace() ServiceCrudOption { return func(o *ServiceCrudOptions) { o.NotSyncToWorkspace = true } } ================================================ FILE: core/interfaces/fs_service_v2.go ================================================ package interfaces type FsServiceV2 interface { List(path string) (files []FsFileInfo, err error) GetFile(path string) (data []byte, err error) GetFileInfo(path string) (file FsFileInfo, err error) Save(path string, data []byte) (err error) CreateDir(path string) (err error) Rename(path, newPath string) (err error) Delete(path string) (err error) Copy(path, newPath string) (err error) Export() (resultPath string, err error) } ================================================ FILE: core/interfaces/grpc_base.go ================================================ package interfaces type GrpcBase interface { WithConfigPath Init() (err error) Start() (err error) Stop() (err error) Register() (err error) } ================================================ FILE: core/interfaces/grpc_base_service_params.go ================================================ package interfaces type GrpcBaseServiceParams interface { Entity } ================================================ FILE: core/interfaces/grpc_client.go ================================================ package interfaces import ( "context" grpc "github.com/crawlab-team/crawlab/grpc" "time" ) type GrpcClient interface { GrpcBase WithConfigPath GetModelDelegateClient() grpc.ModelDelegateClient GetModelBaseServiceClient() grpc.ModelBaseServiceClient GetNodeClient() grpc.NodeServiceClient GetTaskClient() grpc.TaskServiceClient GetMessageClient() grpc.MessageServiceClient SetAddress(Address) SetTimeout(time.Duration) SetSubscribeType(string) SetHandleMessage(bool) Context() (context.Context, context.CancelFunc) NewRequest(interface{}) *grpc.Request GetMessageChannel() chan *grpc.StreamMessage Restart() error NewModelBaseServiceRequest(ModelId, GrpcBaseServiceParams) (*grpc.Request, error) IsStarted() bool IsClosed() bool Err() error GetStream() grpc.NodeService_SubscribeClient } ================================================ FILE: core/interfaces/grpc_client_model_base_service.go ================================================ package interfaces type GrpcClientModelBaseService interface { WithModelId WithConfigPath ModelBaseService } ================================================ FILE: core/interfaces/grpc_client_model_delegate.go ================================================ package interfaces type GrpcClientModelDelegate interface { ModelDelegate WithConfigPath Close() error } ================================================ FILE: core/interfaces/grpc_client_model_environment_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcClientModelEnvironmentService interface { ModelBaseService GetEnvironmentById(id primitive.ObjectID) (s Environment, err error) GetEnvironment(query bson.M, opts *mongo.FindOptions) (s Environment, err error) GetEnvironmentList(query bson.M, opts *mongo.FindOptions) (res []Environment, err error) } ================================================ FILE: core/interfaces/grpc_client_model_node_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcClientModelNodeService interface { ModelBaseService GetNodeById(id primitive.ObjectID) (n Node, err error) GetNode(query bson.M, opts *mongo.FindOptions) (n Node, err error) GetNodeByKey(key string) (n Node, err error) GetNodeList(query bson.M, opts *mongo.FindOptions) (res []Node, err error) } ================================================ FILE: core/interfaces/grpc_client_model_service.go ================================================ package interfaces type GrpcClientModelService interface { WithConfigPath NewBaseServiceDelegate(id ModelId) (GrpcClientModelBaseService, error) } ================================================ FILE: core/interfaces/grpc_client_model_spider_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcClientModelSpiderService interface { ModelBaseService GetSpiderById(id primitive.ObjectID) (s Spider, err error) GetSpider(query bson.M, opts *mongo.FindOptions) (s Spider, err error) GetSpiderList(query bson.M, opts *mongo.FindOptions) (res []Spider, err error) } ================================================ FILE: core/interfaces/grpc_client_model_task_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcClientModelTaskService interface { ModelBaseService GetTaskById(id primitive.ObjectID) (s Task, err error) GetTask(query bson.M, opts *mongo.FindOptions) (s Task, err error) GetTaskList(query bson.M, opts *mongo.FindOptions) (res []Task, err error) } ================================================ FILE: core/interfaces/grpc_client_model_task_stat_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type GrpcClientModelTaskStatService interface { ModelBaseService GetTaskStatById(id primitive.ObjectID) (s TaskStat, err error) GetTaskStat(query bson.M, opts *mongo.FindOptions) (s TaskStat, err error) GetTaskStatList(query bson.M, opts *mongo.FindOptions) (res []TaskStat, err error) } ================================================ FILE: core/interfaces/grpc_client_pool.go ================================================ package interfaces type GrpcClientPool interface { WithConfigPath Init() error NewClient() error GetClient() (GrpcClient, error) SetSize(int) } ================================================ FILE: core/interfaces/grpc_model_base_service_message.go ================================================ package interfaces type GrpcModelBaseServiceMessage interface { GetModelId() ModelId GetData() []byte ToBytes() (data []byte) } ================================================ FILE: core/interfaces/grpc_model_binder.go ================================================ package interfaces type GrpcModelBinder interface { ModelBinder } ================================================ FILE: core/interfaces/grpc_model_delegate_message.go ================================================ package interfaces type GrpcModelDelegateMessage interface { GetModelId() ModelId GetMethod() ModelDelegateMethod GetData() []byte ToBytes() (data []byte) } ================================================ FILE: core/interfaces/grpc_model_list_binder.go ================================================ package interfaces type GrpcModelListBinder interface { ModelListBinder } ================================================ FILE: core/interfaces/grpc_server.go ================================================ package interfaces import ( grpc "github.com/crawlab-team/crawlab/grpc" ) type GrpcServer interface { GrpcBase SetAddress(Address) GetSubscribe(key string) (sub GrpcSubscribe, err error) SetSubscribe(key string, sub GrpcSubscribe) DeleteSubscribe(key string) SendStreamMessage(key string, code grpc.StreamMessageCode) (err error) SendStreamMessageWithData(nodeKey string, code grpc.StreamMessageCode, d interface{}) (err error) IsStopped() (res bool) } ================================================ FILE: core/interfaces/grpc_stream.go ================================================ package interfaces import grpc "github.com/crawlab-team/crawlab/grpc" type GrpcStream interface { Send(msg *grpc.StreamMessage) (err error) } type GrpcStreamBidirectional interface { GrpcStream Recv() (msg *grpc.StreamMessage, err error) } ================================================ FILE: core/interfaces/grpc_subscribe.go ================================================ package interfaces type GrpcSubscribe interface { GetStream() GrpcStream GetStreamBidirectional() GrpcStreamBidirectional GetFinished() chan bool } ================================================ FILE: core/interfaces/i18n_service.go ================================================ package interfaces type I18nService interface { AddTranslations(t []Translation) GetTranslations() (t []Translation) } ================================================ FILE: core/interfaces/injectable.go ================================================ package interfaces type Injectable interface { Inject() error } ================================================ FILE: core/interfaces/list.go ================================================ package interfaces type List interface { GetModels() (res []Model) } ================================================ FILE: core/interfaces/model.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type Model interface { GetId() (id primitive.ObjectID) SetId(id primitive.ObjectID) } type ModelV2 interface { GetId() (id primitive.ObjectID) SetId(id primitive.ObjectID) SetCreated(by primitive.ObjectID) SetUpdated(by primitive.ObjectID) } type ModelId int const ( ModelIdArtifact = iota ModelIdTag ModelIdNode ModelIdProject ModelIdSpider ModelIdTask ModelIdJob ModelIdSchedule ModelIdUser ModelIdSetting ModelIdToken ModelIdVariable ModelIdTaskQueue ModelIdTaskStat ModelIdSpiderStat ModelIdDataSource ModelIdDataCollection ModelIdResult ModelIdPassword ModelIdExtraValue ModelIdGit ModelIdRole ModelIdUserRole ModelIdPermission ModelIdRolePermission ModelIdEnvironment ModelIdDependencySetting ) const ( ModelColNameArtifact = "artifacts" ModelColNameTag = "tags" ModelColNameNode = "nodes" ModelColNameProject = "projects" ModelColNameSpider = "spiders" ModelColNameTask = "tasks" ModelColNameJob = "jobs" ModelColNameSchedule = "schedules" ModelColNameUser = "users" ModelColNameSetting = "settings" ModelColNameToken = "tokens" ModelColNameVariable = "variables" ModelColNameTaskQueue = "task_queue" ModelColNameTaskStat = "task_stats" ModelColNameSpiderStat = "spider_stats" ModelColNameDataSource = "data_sources" ModelColNameDataCollection = "data_collections" ModelColNamePasswords = "passwords" ModelColNameExtraValues = "extra_values" ModelColNameGit = "gits" ModelColNameRole = "roles" ModelColNameUserRole = "user_roles" ModelColNamePermission = "permissions" ModelColNameRolePermission = "role_permissions" ModelColNameEnvironment = "environments" ModelColNameDependencySetting = "dependency_settings" ) type ModelWithTags interface { Model SetTags(tags []Tag) GetTags() (tags []Tag) } type ModelWithNameDescription interface { Model GetName() (name string) SetName(name string) GetDescription() (description string) SetDescription(description string) } type ModelWithKey interface { Model GetKey() (key string) SetKey(key string) } ================================================ FILE: core/interfaces/model_artifact.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type ModelArtifact interface { Model GetSys() (sys ModelArtifactSys) GetTagIds() (ids []primitive.ObjectID) SetTagIds(ids []primitive.ObjectID) SetObj(obj Model) SetDel(del bool) } ================================================ FILE: core/interfaces/model_artifact_sys.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type ModelArtifactSys interface { GetCreateTs() time.Time SetCreateTs(ts time.Time) GetUpdateTs() time.Time SetUpdateTs(ts time.Time) GetDeleteTs() time.Time SetDeleteTs(ts time.Time) GetCreateUid() primitive.ObjectID SetCreateUid(id primitive.ObjectID) GetUpdateUid() primitive.ObjectID SetUpdateUid(id primitive.ObjectID) GetDeleteUid() primitive.ObjectID SetDeleteUid(id primitive.ObjectID) } ================================================ FILE: core/interfaces/model_base_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type ModelBaseService interface { GetModelId() (id ModelId) SetModelId(id ModelId) GetById(id primitive.ObjectID) (res Model, err error) Get(query bson.M, opts *mongo.FindOptions) (res Model, err error) GetList(query bson.M, opts *mongo.FindOptions) (res List, err error) DeleteById(id primitive.ObjectID, args ...interface{}) (err error) Delete(query bson.M, args ...interface{}) (err error) DeleteList(query bson.M, args ...interface{}) (err error) ForceDeleteList(query bson.M, args ...interface{}) (err error) UpdateById(id primitive.ObjectID, update bson.M, args ...interface{}) (err error) Update(query bson.M, update bson.M, fields []string, args ...interface{}) (err error) UpdateDoc(query bson.M, doc Model, fields []string, args ...interface{}) (err error) Insert(u User, docs ...interface{}) (err error) Count(query bson.M) (total int, err error) } type ModelService interface { GetBaseService(id ModelId) (svc ModelBaseService) } ================================================ FILE: core/interfaces/model_binder.go ================================================ package interfaces type ModelBinder interface { Bind() (res Model, err error) Process(d Model) (res Model, err error) } ================================================ FILE: core/interfaces/model_delegate.go ================================================ package interfaces type ModelDelegateMethod string type ModelDelegate interface { Add() error Save() error Delete() error GetArtifact() (ModelArtifact, error) GetModel() Model Refresh() error ToBytes(interface{}) ([]byte, error) } const ( ModelDelegateMethodAdd = "add" ModelDelegateMethodSave = "save" ModelDelegateMethodDelete = "delete" ModelDelegateMethodGetArtifact = "get-artifact" ModelDelegateMethodRefresh = "refresh" ModelDelegateMethodChange = "change" ) ================================================ FILE: core/interfaces/model_environment.go ================================================ package interfaces type Environment interface { Model GetKey() (key string) SetKey(key string) GetValue() (value string) SetValue(value string) } ================================================ FILE: core/interfaces/model_extra_value.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type ExtraValue interface { Model GetValue() (v interface{}) SetValue(v interface{}) GetObjectId() (oid primitive.ObjectID) SetObjectId(oid primitive.ObjectID) GetModel() (m string) SetModel(m string) GetType() (t string) SetType(t string) } ================================================ FILE: core/interfaces/model_git.go ================================================ package interfaces // Git interface type Git interface { Model GetUrl() (url string) SetUrl(url string) GetAuthType() (authType string) SetAuthType(authType string) GetUsername() (username string) SetUsername(username string) GetPassword() (password string) SetPassword(password string) GetCurrentBranch() (currentBranch string) SetCurrentBranch(currentBranch string) GetAutoPull() (autoPull bool) SetAutoPull(autoPull bool) } ================================================ FILE: core/interfaces/model_list_binder.go ================================================ package interfaces type ModelListBinder interface { Bind() (l List, err error) Process(d interface{}) (l List, err error) } ================================================ FILE: core/interfaces/model_node.go ================================================ package interfaces import "time" type Node interface { ModelWithNameDescription GetKey() (key string) GetIsMaster() (ok bool) GetActive() (active bool) SetActive(active bool) SetActiveTs(activeTs time.Time) GetStatus() (status string) SetStatus(status string) GetEnabled() (enabled bool) SetEnabled(enabled bool) GetAvailableRunners() (runners int) SetAvailableRunners(runners int) GetMaxRunners() (runners int) SetMaxRunners(runners int) IncrementAvailableRunners() DecrementAvailableRunners() } ================================================ FILE: core/interfaces/model_node_delegate.go ================================================ package interfaces import "time" type ModelNodeDelegate interface { ModelDelegate UpdateStatus(active bool, activeTs *time.Time, status string) (err error) UpdateStatusOnline() (err error) UpdateStatusOffline() (err error) } ================================================ FILE: core/interfaces/model_permission.go ================================================ package interfaces type Permission interface { ModelWithKey ModelWithNameDescription GetType() (t string) SetType(t string) GetTarget() (target []string) SetTarget(target []string) GetAllow() (allow []string) SetAllow(allow []string) GetDeny() (deny []string) SetDeny(deny []string) } ================================================ FILE: core/interfaces/model_result.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type Result interface { Value() map[string]interface{} SetValue(key string, value interface{}) GetValue(key string) (value interface{}) GetTaskId() (id primitive.ObjectID) SetTaskId(id primitive.ObjectID) } ================================================ FILE: core/interfaces/model_role.go ================================================ package interfaces type Role interface { ModelWithKey ModelWithNameDescription } ================================================ FILE: core/interfaces/model_schedule.go ================================================ package interfaces import ( "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson/primitive" ) type Schedule interface { Model GetEnabled() (enabled bool) SetEnabled(enabled bool) GetEntryId() (id cron.EntryID) SetEntryId(id cron.EntryID) GetCron() (c string) SetCron(c string) GetSpiderId() (id primitive.ObjectID) SetSpiderId(id primitive.ObjectID) GetMode() (mode string) SetMode(mode string) GetNodeIds() (ids []primitive.ObjectID) SetNodeIds(ids []primitive.ObjectID) GetCmd() (cmd string) SetCmd(cmd string) GetParam() (param string) SetParam(param string) GetPriority() (p int) SetPriority(p int) } ================================================ FILE: core/interfaces/model_service_v2.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type ModelServiceV2[T any] interface { GetById(id primitive.ObjectID) (model *T, err error) Get(query bson.M, options *mongo.FindOptions) (model *T, err error) GetList(query bson.M, options *mongo.FindOptions) (models []T, err error) DeleteById(id primitive.ObjectID) (err error) Delete(query bson.M) (err error) DeleteList(query bson.M) (err error) UpdateById(id primitive.ObjectID, update bson.M) (err error) UpdateOne(query bson.M, update bson.M) (err error) UpdateMany(query bson.M, update bson.M) (err error) ReplaceById(id primitive.ObjectID, model T) (err error) Replace(query bson.M, model T) (err error) InsertOne(model T) (id primitive.ObjectID, err error) InsertMany(models []T) (ids []primitive.ObjectID, err error) Count(query bson.M) (total int, err error) GetCol() (col *mongo.Col) } ================================================ FILE: core/interfaces/model_spider.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type Spider interface { ModelWithNameDescription GetType() (ty string) GetMode() (mode string) SetMode(mode string) GetNodeIds() (ids []primitive.ObjectID) SetNodeIds(ids []primitive.ObjectID) GetCmd() (cmd string) SetCmd(cmd string) GetParam() (param string) SetParam(param string) GetPriority() (p int) SetPriority(p int) GetColId() (id primitive.ObjectID) SetColId(id primitive.ObjectID) GetIncrementalSync() (incrementalSync bool) SetIncrementalSync(incrementalSync bool) GetAutoInstall() (autoInstall bool) SetAutoInstall(autoInstall bool) } ================================================ FILE: core/interfaces/model_tag.go ================================================ package interfaces type Tag interface { Model GetName() string GetColor() string SetCol(string) } ================================================ FILE: core/interfaces/model_task.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type Task interface { Model GetNodeId() (id primitive.ObjectID) SetNodeId(id primitive.ObjectID) GetNodeIds() (ids []primitive.ObjectID) GetStatus() (status string) SetStatus(status string) GetError() (error string) SetError(error string) GetPid() (pid int) SetPid(pid int) GetSpiderId() (id primitive.ObjectID) GetType() (ty string) GetCmd() (cmd string) GetParam() (param string) GetPriority() (p int) GetUserId() (id primitive.ObjectID) SetUserId(id primitive.ObjectID) } ================================================ FILE: core/interfaces/model_task_stat.go ================================================ package interfaces import "time" type TaskStat interface { Model GetCreateTs() (ts time.Time) SetCreateTs(ts time.Time) GetStartTs() (ts time.Time) SetStartTs(ts time.Time) GetEndTs() (ts time.Time) SetEndTs(ts time.Time) GetWaitDuration() (d int64) SetWaitDuration(d int64) GetRuntimeDuration() (d int64) SetRuntimeDuration(d int64) GetTotalDuration() (d int64) SetTotalDuration(d int64) GetResultCount() (c int64) SetResultCount(c int64) GetErrorLogCount() (c int64) SetErrorLogCount(c int64) } ================================================ FILE: core/interfaces/model_user.go ================================================ package interfaces type User interface { Model GetUsername() (name string) GetPassword() (p string) GetRole() (r string) GetEmail() (email string) } ================================================ FILE: core/interfaces/model_user_group.go ================================================ package interfaces type UserGroup interface { Model GetUsers() (users []User, err error) } ================================================ FILE: core/interfaces/module.go ================================================ package interfaces type ModuleId int type Module interface { Init() error Start() Wait() Stop() } ================================================ FILE: core/interfaces/node_config_service.go ================================================ package interfaces type NodeConfigService interface { WithConfigPath Init() error Reload() error GetBasicNodeInfo() Entity GetNodeKey() string GetNodeName() string IsMaster() bool GetAuthKey() string GetMaxRunners() int } ================================================ FILE: core/interfaces/node_master_service.go ================================================ package interfaces import ( "time" ) type NodeMasterService interface { NodeService Monitor() SetMonitorInterval(duration time.Duration) Register() error StopOnError() GetServer() GrpcServer } ================================================ FILE: core/interfaces/node_service.go ================================================ package interfaces type NodeService interface { Module WithConfigPath WithAddress GetConfigService() NodeConfigService } ================================================ FILE: core/interfaces/node_service_option.go ================================================ package interfaces type NodeServiceOption interface { } ================================================ FILE: core/interfaces/node_worker_service.go ================================================ package interfaces import "time" type NodeWorkerService interface { NodeService Register() Recv() ReportStatus() SetHeartbeatInterval(duration time.Duration) } ================================================ FILE: core/interfaces/options.go ================================================ package interfaces ================================================ FILE: core/interfaces/process_daemon.go ================================================ package interfaces import ( "os/exec" "time" ) type ProcessDaemon interface { Start() (err error) Stop() GetMaxErrors() (maxErrors int) SetMaxErrors(maxErrors int) GetExitTimeout() (timeout time.Duration) SetExitTimeout(timeout time.Duration) GetCmd() (cmd *exec.Cmd) GetCh() (ch chan int) } ================================================ FILE: core/interfaces/provide.go ================================================ package interfaces type Provide func(env string) ================================================ FILE: core/interfaces/result_service.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/generic" "time" ) type ResultService interface { Insert(records ...interface{}) (err error) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) Count(query generic.ListQuery) (n int, err error) Index(fields []string) SetTime(t time.Time) GetTime() (t time.Time) } ================================================ FILE: core/interfaces/result_service_mongo.go ================================================ package interfaces import ( "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type ResultServiceMongo interface { GetId() (id primitive.ObjectID) SetId(id primitive.ObjectID) List(query bson.M, opts *mongo.FindOptions) (results []Result, err error) Count(query bson.M) (total int, err error) Insert(docs ...interface{}) (err error) } ================================================ FILE: core/interfaces/result_service_registry.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type ResultServiceRegistry interface { Register(key string, fn ResultServiceRegistryFn) Unregister(key string) Get(key string) (fn ResultServiceRegistryFn) } type ResultServiceRegistryFn func(colId primitive.ObjectID, dsId primitive.ObjectID) (ResultService, error) ================================================ FILE: core/interfaces/schedule_service.go ================================================ package interfaces import ( "github.com/robfig/cron/v3" "time" ) type ScheduleService interface { WithConfigPath Module GetLocation() (loc *time.Location) SetLocation(loc *time.Location) GetDelay() (delay bool) SetDelay(delay bool) GetSkip() (skip bool) SetSkip(skip bool) GetUpdateInterval() (interval time.Duration) SetUpdateInterval(interval time.Duration) Enable(s Schedule, args ...interface{}) (err error) Disable(s Schedule, args ...interface{}) (err error) Update() GetCron() (c *cron.Cron) } ================================================ FILE: core/interfaces/spider_admin_service.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type SpiderAdminService interface { WithConfigPath Start() (err error) // Schedule a new task of the spider Schedule(id primitive.ObjectID, opts *SpiderRunOptions) (taskIds []primitive.ObjectID, err error) // Clone the spider Clone(id primitive.ObjectID, opts *SpiderCloneOptions) (err error) // Delete the spider Delete(id primitive.ObjectID) (err error) // SyncGit syncs all git repositories SyncGit() (err error) // SyncGitOne syncs one git repository SyncGitOne(g Git) (err error) // Export exports the spider and return zip file path Export(id primitive.ObjectID) (filePath string, err error) } ================================================ FILE: core/interfaces/spider_service_options.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type SpiderRunOptions struct { Mode string `json:"mode"` NodeIds []primitive.ObjectID `json:"node_ids"` Cmd string `json:"cmd"` Param string `json:"param"` ScheduleId primitive.ObjectID `json:"schedule_id"` Priority int `json:"priority"` UserId primitive.ObjectID `json:"-"` } type SpiderCloneOptions struct { Name string } ================================================ FILE: core/interfaces/stats_service.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson" type StatsService interface { GetOverviewStats(query bson.M) (data interface{}, err error) GetDailyStats(query bson.M) (data interface{}, err error) GetTaskStats(query bson.M) (data interface{}, err error) } ================================================ FILE: core/interfaces/task_base_service.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type TaskBaseService interface { WithConfigPath Module SaveTask(t Task, status string) (err error) IsStopped() (res bool) GetQueue(nodeId primitive.ObjectID) (queue string) } ================================================ FILE: core/interfaces/task_handler_service.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type TaskHandlerService interface { TaskBaseService // Run task and execute locally Run(taskId primitive.ObjectID) (err error) // Cancel task locally Cancel(taskId primitive.ObjectID) (err error) // Fetch tasks and run Fetch() // ReportStatus periodically report handler status to master ReportStatus() // Reset reset internals to default Reset() // IsSyncLocked whether the given task is locked for files sync IsSyncLocked(path string) (ok bool) // LockSync lock files sync for given task LockSync(path string) // UnlockSync unlock files sync for given task UnlockSync(path string) // GetExitWatchDuration get max runners GetExitWatchDuration() (duration time.Duration) // SetExitWatchDuration set max runners SetExitWatchDuration(duration time.Duration) // GetFetchInterval get report interval GetFetchInterval() (interval time.Duration) // SetFetchInterval set report interval SetFetchInterval(interval time.Duration) // GetReportInterval get report interval GetReportInterval() (interval time.Duration) // SetReportInterval set report interval SetReportInterval(interval time.Duration) // GetCancelTimeout get report interval GetCancelTimeout() (timeout time.Duration) // SetCancelTimeout set report interval SetCancelTimeout(timeout time.Duration) // GetModelService get model service GetModelService() (modelSvc GrpcClientModelService) // GetModelSpiderService get model spider service GetModelSpiderService() (modelSpiderSvc GrpcClientModelSpiderService) // GetModelTaskService get model task service GetModelTaskService() (modelTaskSvc GrpcClientModelTaskService) // GetModelTaskStatService get model task stat service GetModelTaskStatService() (modelTaskStatSvc GrpcClientModelTaskStatService) // GetModelEnvironmentService get model environment service GetModelEnvironmentService() (modelEnvironmentSvc GrpcClientModelEnvironmentService) // GetNodeConfigService get node config service GetNodeConfigService() (cfgSvc NodeConfigService) // GetCurrentNode get node of the handler GetCurrentNode() (n Node, err error) // GetTaskById get task by id GetTaskById(id primitive.ObjectID) (t Task, err error) // GetSpiderById get task by id GetSpiderById(id primitive.ObjectID) (t Spider, err error) } ================================================ FILE: core/interfaces/task_hook_service.go ================================================ package interfaces type TaskHookService interface { PreActions(Task, Spider, FsServiceV2, TaskHandlerService) (err error) PostActions(Task, Spider, FsServiceV2, TaskHandlerService) (err error) } ================================================ FILE: core/interfaces/task_runner.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type TaskRunner interface { Init() (err error) Run() (err error) Cancel() (err error) SetSubscribeTimeout(timeout time.Duration) GetTaskId() (id primitive.ObjectID) CleanUp() (err error) } ================================================ FILE: core/interfaces/task_scheduler_service.go ================================================ package interfaces import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type TaskSchedulerService interface { TaskBaseService // Enqueue task into the task queue Enqueue(t Task) (t2 Task, err error) // Cancel task to corresponding node Cancel(id primitive.ObjectID, args ...interface{}) (err error) // SetInterval set the interval or duration between two adjacent fetches SetInterval(interval time.Duration) } ================================================ FILE: core/interfaces/task_stats_service.go ================================================ package interfaces import "go.mongodb.org/mongo-driver/bson/primitive" type TaskStatsService interface { TaskBaseService InsertData(id primitive.ObjectID, records ...interface{}) (err error) InsertLogs(id primitive.ObjectID, logs ...string) (err error) } ================================================ FILE: core/interfaces/test.go ================================================ package interfaces import "testing" type Test interface { Setup(*testing.T) Cleanup() } ================================================ FILE: core/interfaces/translation.go ================================================ package interfaces type Translation interface { GetLang() (l string) } ================================================ FILE: core/interfaces/user_service.go ================================================ package interfaces import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "go.mongodb.org/mongo-driver/bson/primitive" ) type UserService interface { Init() (err error) SetJwtSecret(secret string) SetJwtSigningMethod(method jwt.SigningMethod) Create(opts *UserCreateOptions, args ...interface{}) (err error) Login(opts *UserLoginOptions) (token string, u User, err error) CheckToken(token string) (u User, err error) ChangePassword(id primitive.ObjectID, password string, args ...interface{}) (err error) MakeToken(user User) (tokenStr string, err error) GetCurrentUser(c *gin.Context) (u User, err error) } ================================================ FILE: core/interfaces/user_service_options.go ================================================ package interfaces type UserCreateOptions struct { Username string Password string Email string Role string } type UserLoginOptions struct { Username string Password string } ================================================ FILE: core/interfaces/with_address.go ================================================ package interfaces type WithAddress interface { GetAddress() (address Address) SetAddress(address Address) } ================================================ FILE: core/interfaces/with_config_path.go ================================================ package interfaces type WithConfigPath interface { GetConfigPath() (path string) SetConfigPath(path string) } ================================================ FILE: core/interfaces/with_model_id.go ================================================ package interfaces type WithModelId interface { GetModelId() (id ModelId) SetModelId(id ModelId) } ================================================ FILE: core/main.go ================================================ package main func main() { } ================================================ FILE: core/middlewares/auth.go ================================================ package middlewares import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/user" "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "github.com/spf13/viper" ) func AuthorizationMiddleware() gin.HandlerFunc { userSvc, _ := user.GetUserService() return func(c *gin.Context) { // disable auth for test if viper.GetBool("auth.disabled") { modelSvc, err := service.GetService() if err != nil { utils.HandleErrorInternalServerError(c, err) return } u, err := modelSvc.GetUserByUsername(constants.DefaultAdminUsername, nil) if err != nil { utils.HandleErrorInternalServerError(c, err) return } c.Set(constants.UserContextKey, u) c.Next() return } // token string tokenStr := c.GetHeader("Authorization") // validate token u, err := userSvc.CheckToken(tokenStr) if err != nil { // validation failed, return error response utils.HandleErrorUnauthorized(c, errors.ErrorHttpUnauthorized) return } // set user in context c.Set(constants.UserContextKey, u) // validation success c.Next() } } ================================================ FILE: core/middlewares/auth_v2.go ================================================ package middlewares import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/user" "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "github.com/spf13/viper" ) func AuthorizationMiddlewareV2() gin.HandlerFunc { userSvc, _ := user.GetUserServiceV2() return func(c *gin.Context) { // disable auth for test if viper.GetBool("auth.disabled") { modelSvc, err := service.GetService() if err != nil { utils.HandleErrorInternalServerError(c, err) return } u, err := modelSvc.GetUserByUsername(constants.DefaultAdminUsername, nil) if err != nil { utils.HandleErrorInternalServerError(c, err) return } c.Set(constants.UserContextKey, u) c.Next() return } // token string tokenStr := c.GetHeader("Authorization") // validate token u, err := userSvc.CheckToken(tokenStr) if err != nil { // validation failed, return error response utils.HandleErrorUnauthorized(c, errors.ErrorHttpUnauthorized) return } // set user in context c.Set(constants.UserContextKey, u) // validation success c.Next() } } ================================================ FILE: core/middlewares/cors.go ================================================ 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() } } ================================================ FILE: core/middlewares/filer_auth.go ================================================ package middlewares import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/utils" "github.com/gin-gonic/gin" "github.com/spf13/viper" ) func FilerAuthorizationMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // auth key authKey := c.GetHeader("Authorization") // server auth key svrAuthKey := viper.GetString("fs.filer.authKey") // skip to next if no server auth key is provided if svrAuthKey == "" { c.Next() return } // validate if authKey != svrAuthKey { // validation failed, return error response utils.HandleErrorUnauthorized(c, errors.ErrorHttpUnauthorized) return } // validation success c.Next() } } ================================================ FILE: core/middlewares/middlewares.go ================================================ package middlewares import "github.com/gin-gonic/gin" func InitMiddlewares(app *gin.Engine) (err error) { // default logger app.Use(gin.Logger()) // recovery from panics app.Use(gin.Recovery()) // cors app.Use(CORSMiddleware()) return nil } ================================================ FILE: core/models/client/binder_basic.go ================================================ package client import ( "encoding/json" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" ) func NewBasicBinder(id interfaces.ModelId, res *grpc.Response) (b interfaces.GrpcModelBinder) { return &BasicBinder{ id: id, res: res, } } type BasicBinder struct { id interfaces.ModelId res *grpc.Response } func (b *BasicBinder) Bind() (res interfaces.Model, err error) { m := models.NewModelMap() switch b.id { case interfaces.ModelIdArtifact: return b.Process(&m.Artifact) case interfaces.ModelIdTag: return b.Process(&m.Tag) case interfaces.ModelIdNode: return b.Process(&m.Node) case interfaces.ModelIdProject: return b.Process(&m.Project) case interfaces.ModelIdSpider: return b.Process(&m.Spider) case interfaces.ModelIdTask: return b.Process(&m.Task) case interfaces.ModelIdJob: return b.Process(&m.Job) case interfaces.ModelIdSchedule: return b.Process(&m.Schedule) case interfaces.ModelIdUser: return b.Process(&m.User) case interfaces.ModelIdSetting: return b.Process(&m.Setting) case interfaces.ModelIdToken: return b.Process(&m.Token) case interfaces.ModelIdVariable: return b.Process(&m.Variable) case interfaces.ModelIdTaskQueue: return b.Process(&m.TaskQueueItem) case interfaces.ModelIdTaskStat: return b.Process(&m.TaskStat) case interfaces.ModelIdSpiderStat: return b.Process(&m.SpiderStat) case interfaces.ModelIdDataSource: return b.Process(&m.DataSource) case interfaces.ModelIdDataCollection: return b.Process(&m.DataCollection) case interfaces.ModelIdResult: return b.Process(&m.Result) case interfaces.ModelIdPassword: return b.Process(&m.Password) case interfaces.ModelIdExtraValue: return b.Process(&m.ExtraValue) case interfaces.ModelIdGit: return b.Process(&m.Git) case interfaces.ModelIdRole: return b.Process(&m.Role) case interfaces.ModelIdUserRole: return b.Process(&m.UserRole) case interfaces.ModelIdPermission: return b.Process(&m.Permission) case interfaces.ModelIdRolePermission: return b.Process(&m.RolePermission) case interfaces.ModelIdEnvironment: return b.Process(&m.Environment) case interfaces.ModelIdDependencySetting: return b.Process(&m.DependencySetting) default: return nil, errors.ErrorModelInvalidModelId } } func (b *BasicBinder) Process(d interfaces.Model) (res interfaces.Model, err error) { if err := json.Unmarshal(b.res.Data, d); err != nil { return nil, trace.TraceError(err) } return d, nil } ================================================ FILE: core/models/client/binder_list.go ================================================ package client import ( "encoding/json" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" ) func NewListBinder(id interfaces.ModelId, res *grpc.Response) (b interfaces.GrpcModelListBinder) { return &ListBinder{ id: id, res: res, } } type ListBinder struct { id interfaces.ModelId res *grpc.Response } func (b *ListBinder) Bind() (l interfaces.List, err error) { m := models.NewModelListMap() switch b.id { case interfaces.ModelIdArtifact: return b.Process(&m.Artifacts) case interfaces.ModelIdTag: return b.Process(&m.Tags) case interfaces.ModelIdNode: return b.Process(&m.Nodes) case interfaces.ModelIdProject: return b.Process(&m.Projects) case interfaces.ModelIdSpider: return b.Process(&m.Spiders) case interfaces.ModelIdTask: return b.Process(&m.Tasks) case interfaces.ModelIdJob: return b.Process(&m.Jobs) case interfaces.ModelIdSchedule: return b.Process(&m.Schedules) case interfaces.ModelIdUser: return b.Process(&m.Users) case interfaces.ModelIdSetting: return b.Process(&m.Settings) case interfaces.ModelIdToken: return b.Process(&m.Tokens) case interfaces.ModelIdVariable: return b.Process(&m.Variables) case interfaces.ModelIdTaskQueue: return b.Process(&m.TaskQueueItems) case interfaces.ModelIdTaskStat: return b.Process(&m.TaskStats) case interfaces.ModelIdSpiderStat: return b.Process(&m.SpiderStats) case interfaces.ModelIdDataSource: return b.Process(&m.DataSources) case interfaces.ModelIdDataCollection: return b.Process(&m.DataCollections) case interfaces.ModelIdResult: return b.Process(&m.Results) case interfaces.ModelIdPassword: return b.Process(&m.Passwords) case interfaces.ModelIdExtraValue: return b.Process(&m.ExtraValues) case interfaces.ModelIdGit: return b.Process(&m.Gits) case interfaces.ModelIdRole: return b.Process(&m.Roles) case interfaces.ModelIdUserRole: return b.Process(&m.UserRoles) case interfaces.ModelIdPermission: return b.Process(&m.PermissionList) case interfaces.ModelIdRolePermission: return b.Process(&m.RolePermissionList) case interfaces.ModelIdEnvironment: return b.Process(&m.Environments) case interfaces.ModelIdDependencySetting: return b.Process(&m.DependencySettings) default: return l, errors.ErrorModelInvalidModelId } } func (b *ListBinder) MustBind() (res interface{}) { res, err := b.Bind() if err != nil { panic(err) } return res } func (b *ListBinder) Process(d interface{}) (l interfaces.List, err error) { if err := json.Unmarshal(b.res.Data, d); err != nil { return l, trace.TraceError(err) } return d.(interfaces.List), nil } ================================================ FILE: core/models/client/model_base_service.go ================================================ package client import ( "encoding/json" "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" errors2 "github.com/pkg/errors" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type BaseServiceDelegate struct { // settings cfgPath string // internals id interfaces.ModelId c interfaces.GrpcClient } func (d *BaseServiceDelegate) GetModelId() (id interfaces.ModelId) { return d.id } func (d *BaseServiceDelegate) SetModelId(id interfaces.ModelId) { d.id = id } func (d *BaseServiceDelegate) GetConfigPath() (path string) { return d.cfgPath } func (d *BaseServiceDelegate) SetConfigPath(path string) { d.cfgPath = path } func (d *BaseServiceDelegate) GetById(id primitive.ObjectID) (doc interfaces.Model, err error) { log.Debugf("[BaseServiceDelegate] get by id[%s]", id.Hex()) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Id: id}) c := d.getModelBaseServiceClient() if c == nil { return nil, trace.TraceError(errors.ErrorModelNilPointer) } log.Debugf("[BaseServiceDelegate] get by id[%s] req: %v", id.Hex(), req) res, err := c.GetById(ctx, req) if err != nil { return nil, trace.TraceError(err) } log.Debugf("[BaseServiceDelegate] get by id[%s] res: %v", id.Hex(), res) return NewBasicBinder(d.id, res).Bind() } func (d *BaseServiceDelegate) Get(query bson.M, opts *mongo.FindOptions) (doc interfaces.Model, err error) { ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, FindOptions: opts}) res, err := d.getModelBaseServiceClient().Get(ctx, req) if err != nil { return nil, err } return NewBasicBinder(d.id, res).Bind() } func (d *BaseServiceDelegate) GetList(query bson.M, opts *mongo.FindOptions) (l interfaces.List, err error) { ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, FindOptions: opts}) res, err := d.getModelBaseServiceClient().GetList(ctx, req) if err != nil { return l, err } return NewListBinder(d.id, res).Bind() } func (d *BaseServiceDelegate) DeleteById(id primitive.ObjectID, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Id: id, User: u}) _, err = d.getModelBaseServiceClient().DeleteById(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) Delete(query bson.M, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, User: u}) _, err = d.getModelBaseServiceClient().Delete(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) DeleteList(query bson.M, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, User: u}) _, err = d.getModelBaseServiceClient().DeleteList(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) ForceDeleteList(query bson.M, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, User: u}) _, err = d.getModelBaseServiceClient().ForceDeleteList(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) UpdateById(id primitive.ObjectID, update bson.M, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Id: id, Update: update, User: u}) _, err = d.getModelBaseServiceClient().UpdateById(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) Update(query bson.M, update bson.M, fields []string, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, Update: update, Fields: fields, User: u}) _, err = d.getModelBaseServiceClient().Update(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) UpdateDoc(query bson.M, doc interfaces.Model, fields []string, args ...interface{}) (err error) { u := utils.GetUserFromArgs(args...) ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query, Doc: doc, Fields: fields, User: u}) _, err = d.getModelBaseServiceClient().UpdateDoc(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) Insert(u interfaces.User, docs ...interface{}) (err error) { ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Docs: docs, User: u}) _, err = d.getModelBaseServiceClient().Insert(ctx, req) if err != nil { return err } return nil } func (d *BaseServiceDelegate) Count(query bson.M) (total int, err error) { ctx, cancel := d.c.Context() defer cancel() req := d.mustNewRequest(&entity.GrpcBaseServiceParams{Query: query}) res, err := d.getModelBaseServiceClient().Count(ctx, req) if err != nil { return total, err } if err := json.Unmarshal(res.Data, &total); err != nil { return total, err } return total, nil } func (d *BaseServiceDelegate) newRequest(params interfaces.GrpcBaseServiceParams) (req *grpc.Request, err error) { return d.c.NewModelBaseServiceRequest(d.id, params) } func (d *BaseServiceDelegate) mustNewRequest(params *entity.GrpcBaseServiceParams) (req *grpc.Request) { req, err := d.newRequest(params) if err != nil { panic(err) } return req } func (d *BaseServiceDelegate) getModelBaseServiceClient() (c grpc.ModelBaseServiceClient) { if err := backoff.Retry(func() (err error) { c = d.c.GetModelBaseServiceClient() if c == nil { err = errors2.New("unable to get model base service client") log.Debugf("[BaseServiceDelegate] err: %v", err) return err } return nil }, backoff.NewConstantBackOff(1*time.Second)); err != nil { trace.PrintError(err) } return c } func NewBaseServiceDelegate(opts ...ModelBaseServiceDelegateOption) (svc2 interfaces.GrpcClientModelBaseService, err error) { // base service svc := &BaseServiceDelegate{} // apply options for _, opt := range opts { opt(svc) } // config path if viper.GetString("config.path") != "" { svc.cfgPath = viper.GetString("config.path") } // dependency injection if err := container.GetContainer().Invoke(func(client interfaces.GrpcClient) { svc.c = client }); err != nil { return nil, err } return svc, nil } func ProvideBaseServiceDelegate(id interfaces.ModelId) func() (svc interfaces.GrpcClientModelBaseService, err error) { return func() (svc interfaces.GrpcClientModelBaseService, err error) { return NewBaseServiceDelegate(WithBaseServiceModelId(id)) } } ================================================ FILE: core/models/client/model_delegate.go ================================================ package client import ( "encoding/json" config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/grpc/client" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/utils" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" ) func NewModelDelegate(doc interfaces.Model, opts ...ModelDelegateOption) interfaces.GrpcClientModelDelegate { switch doc.(type) { case *models.Artifact: return newModelDelegate(interfaces.ModelIdArtifact, doc, opts...) case *models.Tag: return newModelDelegate(interfaces.ModelIdTag, doc, opts...) case *models.Node: return newModelDelegate(interfaces.ModelIdNode, doc, opts...) case *models.Project: return newModelDelegate(interfaces.ModelIdProject, doc, opts...) case *models.Spider: return newModelDelegate(interfaces.ModelIdSpider, doc, opts...) case *models.Task: return newModelDelegate(interfaces.ModelIdTask, doc, opts...) case *models.Job: return newModelDelegate(interfaces.ModelIdJob, doc, opts...) case *models.Schedule: return newModelDelegate(interfaces.ModelIdSchedule, doc, opts...) case *models.User: return newModelDelegate(interfaces.ModelIdUser, doc, opts...) case *models.Setting: return newModelDelegate(interfaces.ModelIdSetting, doc, opts...) case *models.Token: return newModelDelegate(interfaces.ModelIdToken, doc, opts...) case *models.Variable: return newModelDelegate(interfaces.ModelIdVariable, doc, opts...) case *models.TaskQueueItem: return newModelDelegate(interfaces.ModelIdTaskQueue, doc, opts...) case *models.TaskStat: return newModelDelegate(interfaces.ModelIdTaskStat, doc, opts...) case *models.SpiderStat: return newModelDelegate(interfaces.ModelIdSpiderStat, doc, opts...) case *models.DataSource: return newModelDelegate(interfaces.ModelIdDataSource, doc, opts...) case *models.DataCollection: return newModelDelegate(interfaces.ModelIdDataCollection, doc, opts...) case *models.Result: return newModelDelegate(interfaces.ModelIdResult, doc, opts...) case *models.Password: return newModelDelegate(interfaces.ModelIdPassword, doc, opts...) case *models.ExtraValue: return newModelDelegate(interfaces.ModelIdExtraValue, doc, opts...) case *models.Git: return newModelDelegate(interfaces.ModelIdGit, doc, opts...) case *models.UserRole: return newModelDelegate(interfaces.ModelIdUserRole, doc, opts...) case *models.Permission: return newModelDelegate(interfaces.ModelIdPermission, doc, opts...) case *models.RolePermission: return newModelDelegate(interfaces.ModelIdRolePermission, doc, opts...) case *models.Environment: return newModelDelegate(interfaces.ModelIdEnvironment, doc, opts...) case *models.DependencySetting: return newModelDelegate(interfaces.ModelIdDependencySetting, doc, opts...) default: _ = trace.TraceError(errors.ErrorModelInvalidType) return nil } } func newModelDelegate(id interfaces.ModelId, doc interfaces.Model, opts ...ModelDelegateOption) interfaces.GrpcClientModelDelegate { var err error // collection name colName := models.GetModelColName(id) // model delegate d := &ModelDelegate{ id: id, colName: colName, doc: doc, cfgPath: config2.GetConfigPath(), a: &models.Artifact{ Col: colName, }, } // config path if viper.GetString("config.path") != "" { d.cfgPath = viper.GetString("config.path") } // apply options for _, opt := range opts { opt(d) } // grpc client d.c, err = client.GetClient() if err != nil { trace.PrintError(errors.ErrorModelInvalidType) return nil } if !d.c.IsStarted() { if err := d.c.Start(); err != nil { trace.PrintError(err) return nil } } else if d.c.IsClosed() { if err := d.c.Restart(); err != nil { trace.PrintError(err) return nil } } return d } type ModelDelegate struct { // settings cfgPath string // internals id interfaces.ModelId colName string c interfaces.GrpcClient doc interfaces.Model a interfaces.ModelArtifact } func (d *ModelDelegate) Add() (err error) { return d.do(interfaces.ModelDelegateMethodAdd) } func (d *ModelDelegate) Save() (err error) { return d.do(interfaces.ModelDelegateMethodSave) } func (d *ModelDelegate) Delete() (err error) { return d.do(interfaces.ModelDelegateMethodDelete) } func (d *ModelDelegate) GetArtifact() (res interfaces.ModelArtifact, err error) { if err := d.do(interfaces.ModelDelegateMethodGetArtifact); err != nil { return nil, err } return d.a, nil } func (d *ModelDelegate) GetModel() (res interfaces.Model) { return d.doc } func (d *ModelDelegate) Refresh() (err error) { return d.refresh() } func (d *ModelDelegate) GetConfigPath() (path string) { return d.cfgPath } func (d *ModelDelegate) SetConfigPath(path string) { d.cfgPath = path } func (d *ModelDelegate) Close() (err error) { return d.c.Stop() } func (d *ModelDelegate) ToBytes(m interface{}) (bytes []byte, err error) { if m != nil { return utils.JsonToBytes(m) } return json.Marshal(d.doc) } func (d *ModelDelegate) do(method interfaces.ModelDelegateMethod) (err error) { switch method { case interfaces.ModelDelegateMethodAdd: err = d.add() case interfaces.ModelDelegateMethodSave: err = d.save() case interfaces.ModelDelegateMethodDelete: err = d.delete() case interfaces.ModelDelegateMethodGetArtifact, interfaces.ModelDelegateMethodRefresh: return d.refresh() default: return trace.TraceError(errors.ErrorModelInvalidType) } if err != nil { return err } return nil } func (d *ModelDelegate) add() (err error) { ctx, cancel := d.c.Context() defer cancel() method := interfaces.ModelDelegateMethod(interfaces.ModelDelegateMethodAdd) res, err := d.c.GetModelDelegateClient().Do(ctx, d.c.NewRequest(entity.GrpcDelegateMessage{ ModelId: d.id, Method: method, Data: d.mustGetData(), })) if err != nil { return trace.TraceError(err) } if err := d.deserialize(res, method); err != nil { return err } return d.refreshArtifact() } func (d *ModelDelegate) save() (err error) { ctx, cancel := d.c.Context() defer cancel() method := interfaces.ModelDelegateMethod(interfaces.ModelDelegateMethodSave) res, err := d.c.GetModelDelegateClient().Do(ctx, d.c.NewRequest(entity.GrpcDelegateMessage{ ModelId: d.id, Method: method, Data: d.mustGetData(), })) if err != nil { return trace.TraceError(err) } if err := d.deserialize(res, method); err != nil { return err } return d.refreshArtifact() } func (d *ModelDelegate) delete() (err error) { ctx, cancel := d.c.Context() defer cancel() method := interfaces.ModelDelegateMethod(interfaces.ModelDelegateMethodDelete) res, err := d.c.GetModelDelegateClient().Do(ctx, d.c.NewRequest(entity.GrpcDelegateMessage{ ModelId: d.id, Method: method, Data: d.mustGetData(), })) if err != nil { return trace.TraceError(err) } if err := d.deserialize(res, method); err != nil { return err } return d.refreshArtifact() } func (d *ModelDelegate) refresh() (err error) { ctx, cancel := d.c.Context() defer cancel() method := interfaces.ModelDelegateMethod(interfaces.ModelDelegateMethodRefresh) res, err := d.c.GetModelDelegateClient().Do(ctx, d.c.NewRequest(entity.GrpcDelegateMessage{ ModelId: d.id, Method: method, Data: d.mustGetData(), })) if err != nil { return trace.TraceError(err) } if err := d.deserialize(res, method); err != nil { return err } return nil } func (d *ModelDelegate) refreshArtifact() (err error) { _, err = d.getArtifact() return err } func (d *ModelDelegate) getArtifact() (res2 interfaces.ModelArtifact, err error) { ctx, cancel := d.c.Context() defer cancel() method := interfaces.ModelDelegateMethod(interfaces.ModelDelegateMethodGetArtifact) res, err := d.c.GetModelDelegateClient().Do(ctx, d.c.NewRequest(entity.GrpcDelegateMessage{ ModelId: d.id, Method: method, Data: d.mustGetData(), })) if err != nil { return nil, err } if err := d.deserialize(res, method); err != nil { return nil, err } return d.a, nil } func (d *ModelDelegate) mustGetData() (data []byte) { data, err := d.getData() if err != nil { panic(err) } return data } func (d *ModelDelegate) getData() (data []byte, err error) { return json.Marshal(d.doc) } func (d *ModelDelegate) deserialize(res *grpc.Response, method interfaces.ModelDelegateMethod) (err error) { if method == interfaces.ModelDelegateMethodGetArtifact { res, err := NewBasicBinder(interfaces.ModelIdArtifact, res).Bind() if err != nil { return err } a, ok := res.(interfaces.ModelArtifact) if !ok { return trace.TraceError(errors.ErrorModelInvalidType) } d.a = a } else { d.doc, err = NewBasicBinder(d.id, res).Bind() if err != nil { return err } } return nil } ================================================ FILE: core/models/client/model_environment_service.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type EnvironmentServiceDelegate struct { interfaces.GrpcClientModelBaseService } func (svc *EnvironmentServiceDelegate) GetEnvironmentById(id primitive.ObjectID) (e interfaces.Environment, err error) { res, err := svc.GetById(id) if err != nil { return nil, err } s, ok := res.(interfaces.Environment) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *EnvironmentServiceDelegate) GetEnvironment(query bson.M, opts *mongo.FindOptions) (e interfaces.Environment, err error) { res, err := svc.Get(query, opts) if err != nil { return nil, err } s, ok := res.(interfaces.Environment) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *EnvironmentServiceDelegate) GetEnvironmentList(query bson.M, opts *mongo.FindOptions) (res []interfaces.Environment, err error) { list, err := svc.GetList(query, opts) if err != nil { return nil, err } for _, item := range list.GetModels() { s, ok := item.(interfaces.Environment) if !ok { return nil, errors.ErrorModelInvalidType } res = append(res, s) } return res, nil } func NewEnvironmentServiceDelegate() (svc2 interfaces.GrpcClientModelEnvironmentService, err error) { var opts []ModelBaseServiceDelegateOption // apply options opts = append(opts, WithBaseServiceModelId(interfaces.ModelIdEnvironment)) // base service baseSvc, err := NewBaseServiceDelegate(opts...) if err != nil { return nil, err } // service svc := &EnvironmentServiceDelegate{baseSvc} return svc, nil } ================================================ FILE: core/models/client/model_node_delegate.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type ModelNodeDelegate struct { n interfaces.Node interfaces.GrpcClientModelDelegate } func (d *ModelNodeDelegate) UpdateStatus(active bool, activeTs *time.Time, status string) (err error) { d.n.SetActive(active) if activeTs != nil { d.n.SetActiveTs(*activeTs) } d.n.SetStatus(status) return d.Save() } func (d *ModelNodeDelegate) UpdateStatusOnline() (err error) { now := time.Now() return d.UpdateStatus(true, &now, constants.NodeStatusOnline) } func (d *ModelNodeDelegate) UpdateStatusOffline() (err error) { return d.UpdateStatus(false, nil, constants.NodeStatusOffline) } func NewModelNodeDelegate(n interfaces.Node) interfaces.ModelNodeDelegate { return &ModelNodeDelegate{ n: n, GrpcClientModelDelegate: NewModelDelegate(n), } } ================================================ FILE: core/models/client/model_node_service.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type NodeServiceDelegate struct { interfaces.GrpcClientModelBaseService } func (svc *NodeServiceDelegate) GetNodeById(id primitive.ObjectID) (n interfaces.Node, err error) { res, err := svc.GetById(id) if err != nil { return nil, err } s, ok := res.(interfaces.Node) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *NodeServiceDelegate) GetNode(query bson.M, opts *mongo.FindOptions) (n interfaces.Node, err error) { res, err := svc.Get(query, opts) if err != nil { return nil, err } s, ok := res.(interfaces.Node) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *NodeServiceDelegate) GetNodeByKey(key string) (n interfaces.Node, err error) { return svc.GetNode(bson.M{"key": key}, nil) } func (svc *NodeServiceDelegate) GetNodeList(query bson.M, opts *mongo.FindOptions) (res []interfaces.Node, err error) { list, err := svc.GetList(query, opts) if err != nil { return nil, err } for _, item := range list.GetModels() { s, ok := item.(interfaces.Node) if !ok { return nil, errors.ErrorModelInvalidType } res = append(res, s) } return res, nil } func NewNodeServiceDelegate() (svc2 interfaces.GrpcClientModelNodeService, err error) { var opts []ModelBaseServiceDelegateOption // apply options opts = append(opts, WithBaseServiceModelId(interfaces.ModelIdNode)) // base service baseSvc, err := NewBaseServiceDelegate(opts...) if err != nil { return nil, err } // service svc := &NodeServiceDelegate{baseSvc} return svc, nil } ================================================ FILE: core/models/client/model_service.go ================================================ package client import ( config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/interfaces" ) type ServiceDelegate struct { // settings cfgPath string // internals c interfaces.GrpcClient } func (d *ServiceDelegate) GetConfigPath() string { return d.cfgPath } func (d *ServiceDelegate) SetConfigPath(path string) { d.cfgPath = path } func (d *ServiceDelegate) NewBaseServiceDelegate(id interfaces.ModelId) (svc interfaces.GrpcClientModelBaseService, err error) { var opts []ModelBaseServiceDelegateOption opts = append(opts, WithBaseServiceModelId(id)) if d.cfgPath != "" { opts = append(opts, WithBaseServiceConfigPath(d.cfgPath)) } return NewBaseServiceDelegate(opts...) } func NewServiceDelegate() (svc2 interfaces.GrpcClientModelService, err error) { // service delegate svc := &ServiceDelegate{ cfgPath: config2.GetConfigPath(), } // dependency injection if err := container.GetContainer().Invoke(func(client interfaces.GrpcClient) { svc.c = client }); err != nil { return nil, err } return svc, nil } ================================================ FILE: core/models/client/model_service_v2.go ================================================ package client import ( "encoding/json" "github.com/crawlab-team/crawlab/core/grpc/client" "github.com/crawlab-team/crawlab/core/interfaces" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/db/mongo" grpc "github.com/crawlab-team/crawlab/grpc" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "reflect" "sync" ) var ( instanceMap = make(map[string]interface{}) onceMap = make(map[string]*sync.Once) mu sync.Mutex ) type ModelServiceV2[T any] struct { cfg interfaces.NodeConfigService c *client.GrpcClientV2 modelType string } func (svc *ModelServiceV2[T]) GetById(id primitive.ObjectID) (model *T, err error) { ctx, cancel := svc.c.Context() defer cancel() res, err := svc.c.ModelBaseServiceV2Client.GetById(ctx, &grpc.ModelServiceV2GetByIdRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Id: id.Hex(), }) if err != nil { return nil, err } return svc.deserializeOne(res) } func (svc *ModelServiceV2[T]) GetOne(query bson.M, options *mongo.FindOptions) (model *T, err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return nil, err } findOptionsData, err := json.Marshal(options) if err != nil { return nil, err } res, err := svc.c.ModelBaseServiceV2Client.GetOne(ctx, &grpc.ModelServiceV2GetOneRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, FindOptions: findOptionsData, }) if err != nil { return nil, err } return svc.deserializeOne(res) } func (svc *ModelServiceV2[T]) GetMany(query bson.M, options *mongo.FindOptions) (models []T, err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return nil, err } findOptionsData, err := json.Marshal(options) if err != nil { return nil, err } res, err := svc.c.ModelBaseServiceV2Client.GetMany(ctx, &grpc.ModelServiceV2GetManyRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, FindOptions: findOptionsData, }) if err != nil { return nil, err } return svc.deserializeMany(res) } func (svc *ModelServiceV2[T]) DeleteById(id primitive.ObjectID) (err error) { ctx, cancel := svc.c.Context() defer cancel() _, err = svc.c.ModelBaseServiceV2Client.DeleteById(ctx, &grpc.ModelServiceV2DeleteByIdRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Id: id.Hex(), }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) DeleteOne(query bson.M) (err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.DeleteOne(ctx, &grpc.ModelServiceV2DeleteOneRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) DeleteMany(query bson.M) (err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.DeleteMany(ctx, &grpc.ModelServiceV2DeleteManyRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) UpdateById(id primitive.ObjectID, update bson.M) (err error) { ctx, cancel := svc.c.Context() defer cancel() updateData, err := json.Marshal(update) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.UpdateById(ctx, &grpc.ModelServiceV2UpdateByIdRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Id: id.Hex(), Update: updateData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) UpdateOne(query bson.M, update bson.M) (err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return err } updateData, err := json.Marshal(update) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.UpdateOne(ctx, &grpc.ModelServiceV2UpdateOneRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, Update: updateData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) UpdateMany(query bson.M, update bson.M) (err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return err } updateData, err := json.Marshal(update) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.UpdateMany(ctx, &grpc.ModelServiceV2UpdateManyRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, Update: updateData, }) return nil } func (svc *ModelServiceV2[T]) ReplaceById(id primitive.ObjectID, model T) (err error) { ctx, cancel := svc.c.Context() defer cancel() modelData, err := json.Marshal(model) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.ReplaceById(ctx, &grpc.ModelServiceV2ReplaceByIdRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Id: id.Hex(), Model: modelData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) ReplaceOne(query bson.M, model T) (err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return err } modelData, err := json.Marshal(model) if err != nil { return err } _, err = svc.c.ModelBaseServiceV2Client.ReplaceOne(ctx, &grpc.ModelServiceV2ReplaceOneRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, Model: modelData, }) if err != nil { return err } return nil } func (svc *ModelServiceV2[T]) InsertOne(model T) (id primitive.ObjectID, err error) { ctx, cancel := svc.c.Context() defer cancel() modelData, err := json.Marshal(model) if err != nil { return primitive.NilObjectID, err } res, err := svc.c.ModelBaseServiceV2Client.InsertOne(ctx, &grpc.ModelServiceV2InsertOneRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Model: modelData, }) if err != nil { return primitive.NilObjectID, err } return deserialize[primitive.ObjectID](res) //idStr, err := deserialize[string](res) //if err != nil { // return primitive.NilObjectID, err //} //return primitive.ObjectIDFromHex(idStr) } func (svc *ModelServiceV2[T]) InsertMany(models []T) (ids []primitive.ObjectID, err error) { ctx, cancel := svc.c.Context() defer cancel() modelsData, err := json.Marshal(models) if err != nil { return nil, err } res, err := svc.c.ModelBaseServiceV2Client.InsertMany(ctx, &grpc.ModelServiceV2InsertManyRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Models: modelsData, }) if err != nil { return nil, err } return deserialize[[]primitive.ObjectID](res) } func (svc *ModelServiceV2[T]) Count(query bson.M) (total int, err error) { ctx, cancel := svc.c.Context() defer cancel() queryData, err := json.Marshal(query) if err != nil { return 0, err } res, err := svc.c.ModelBaseServiceV2Client.Count(ctx, &grpc.ModelServiceV2CountRequest{ NodeKey: svc.cfg.GetNodeKey(), ModelType: svc.modelType, Query: queryData, }) if err != nil { return 0, err } return deserialize[int](res) } func (svc *ModelServiceV2[T]) GetCol() (col *mongo.Col) { return nil } func (svc *ModelServiceV2[T]) deserializeOne(res *grpc.Response) (result *T, err error) { r, err := deserialize[T](res) if err != nil { return nil, err } return &r, err } func (svc *ModelServiceV2[T]) deserializeMany(res *grpc.Response) (results []T, err error) { return deserialize[[]T](res) } func deserialize[T any](res *grpc.Response) (result T, err error) { err = json.Unmarshal(res.Data, &result) if err != nil { return result, err } return result, nil } func NewModelServiceV2[T any]() *ModelServiceV2[T] { mu.Lock() defer mu.Unlock() var v T t := reflect.TypeOf(v) typeName := t.Name() if _, exists := onceMap[typeName]; !exists { onceMap[typeName] = new(sync.Once) } var instance *ModelServiceV2[T] c := client.GetGrpcClientV2() if !c.IsStarted() { err := c.Start() if err != nil { panic(err) } } onceMap[typeName].Do(func() { instance = &ModelServiceV2[T]{ cfg: nodeconfig.GetNodeConfigService(), c: c, modelType: typeName, } instanceMap[typeName] = instance }) return instanceMap[typeName].(*ModelServiceV2[T]) } ================================================ FILE: core/models/client/model_service_v2_test.go ================================================ package client_test import ( "context" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/grpc/server" "github.com/crawlab-team/crawlab/core/models/client" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/db/mongo" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "testing" "time" ) type TestModel models.TestModelV2 func setupTestDB() { viper.Set("mongo.db", "testdb") } func teardownTestDB() { db := mongo.GetMongoDb("testdb") db.Drop(context.Background()) } func startSvr(svr *server.GrpcServerV2) { err := svr.Start() if err != nil { log.Errorf("failed to start grpc server: %v", err) } } func stopSvr(svr *server.GrpcServerV2) { err := svr.Stop() if err != nil { log.Errorf("failed to stop grpc server: %v", err) } } func TestModelServiceV2_GetById(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() res, err := clientSvc.GetById(m.Id) require.Nil(t, err) assert.Equal(t, res.Id, m.Id) assert.Equal(t, res.Name, m.Name) } func TestModelServiceV2_GetOne(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() res, err := clientSvc.GetOne(bson.M{"name": m.Name}, nil) require.Nil(t, err) assert.Equal(t, res.Id, m.Id) assert.Equal(t, res.Name, m.Name) } func TestModelServiceV2_GetMany(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() res, err := clientSvc.GetMany(bson.M{"name": m.Name}, nil) require.Nil(t, err) assert.Equal(t, len(res), 1) assert.Equal(t, res[0].Id, m.Id) assert.Equal(t, res[0].Name, m.Name) } func TestModelServiceV2_DeleteById(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.DeleteById(m.Id) require.Nil(t, err) res, err := clientSvc.GetById(m.Id) assert.NotNil(t, err) require.Nil(t, res) } func TestModelServiceV2_DeleteOne(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.DeleteOne(bson.M{"name": m.Name}) require.Nil(t, err) res, err := clientSvc.GetOne(bson.M{"name": m.Name}, nil) assert.NotNil(t, err) require.Nil(t, res) } func TestModelServiceV2_DeleteMany(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.DeleteMany(bson.M{"name": m.Name}) require.Nil(t, err) res, err := clientSvc.GetMany(bson.M{"name": m.Name}, nil) require.Nil(t, err) assert.Equal(t, len(res), 0) } func TestModelServiceV2_UpdateById(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.UpdateById(m.Id, bson.M{"$set": bson.M{"name": "New Name"}}) require.Nil(t, err) res, err := clientSvc.GetById(m.Id) require.Nil(t, err) assert.Equal(t, res.Name, "New Name") } func TestModelServiceV2_UpdateOne(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.UpdateOne(bson.M{"name": m.Name}, bson.M{"$set": bson.M{"name": "New Name"}}) require.Nil(t, err) res, err := clientSvc.GetOne(bson.M{"name": "New Name"}, nil) require.Nil(t, err) assert.Equal(t, res.Name, "New Name") } func TestModelServiceV2_UpdateMany(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m1 := TestModel{ Name: "Test Name", } m2 := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() _, err = modelSvc.InsertOne(m1) require.Nil(t, err) _, err = modelSvc.InsertOne(m2) require.Nil(t, err) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() err = clientSvc.UpdateMany(bson.M{"name": "Test Name"}, bson.M{"$set": bson.M{"name": "New Name"}}) require.Nil(t, err) res, err := clientSvc.GetMany(bson.M{"name": "New Name"}, nil) require.Nil(t, err) assert.Equal(t, len(res), 2) } func TestModelServiceV2_ReplaceById(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() m.Name = "New Name" err = clientSvc.ReplaceById(m.Id, m) require.Nil(t, err) res, err := clientSvc.GetById(m.Id) require.Nil(t, err) assert.Equal(t, res.Name, "New Name") } func TestModelServiceV2_ReplaceOne(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) m := TestModel{ Name: "Test Name", } modelSvc := service.NewModelServiceV2[TestModel]() id, err := modelSvc.InsertOne(m) require.Nil(t, err) m.SetId(id) time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() m.Name = "New Name" err = clientSvc.ReplaceOne(bson.M{"name": "Test Name"}, m) require.Nil(t, err) res, err := clientSvc.GetOne(bson.M{"name": "New Name"}, nil) require.Nil(t, err) assert.Equal(t, res.Name, "New Name") } func TestModelServiceV2_InsertOne(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() m := TestModel{ Name: "Test Name", } id, err := clientSvc.InsertOne(m) require.Nil(t, err) res, err := clientSvc.GetById(id) require.Nil(t, err) assert.Equal(t, res.Name, m.Name) } func TestModelServiceV2_InsertMany(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Test Name 1"}, {Name: "Test Name 2"}, } ids, err := clientSvc.InsertMany(testModels) require.Nil(t, err) for i, id := range ids { res, err := clientSvc.GetById(id) require.Nil(t, err) assert.Equal(t, res.Name, testModels[i].Name) } } func TestModelServiceV2_Count(t *testing.T) { setupTestDB() defer teardownTestDB() svr, err := server.NewGrpcServerV2() require.Nil(t, err) go startSvr(svr) defer stopSvr(svr) modelSvc := service.NewModelServiceV2[TestModel]() for i := 0; i < 5; i++ { _, err = modelSvc.InsertOne(TestModel{ Name: "Test Name", }) require.Nil(t, err) } time.Sleep(100 * time.Millisecond) c, err := grpc.NewClient("localhost:9666", grpc.WithTransportCredentials(insecure.NewCredentials())) require.Nil(t, err) c.Connect() clientSvc := client.NewModelServiceV2[TestModel]() count, err := clientSvc.Count(bson.M{}) require.Nil(t, err) assert.Equal(t, count, 5) } ================================================ FILE: core/models/client/model_spider_service.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type SpiderServiceDelegate struct { interfaces.GrpcClientModelBaseService } func (svc *SpiderServiceDelegate) GetSpiderById(id primitive.ObjectID) (s interfaces.Spider, err error) { res, err := svc.GetById(id) if err != nil { return nil, err } s, ok := res.(interfaces.Spider) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *SpiderServiceDelegate) GetSpider(query bson.M, opts *mongo.FindOptions) (s interfaces.Spider, err error) { res, err := svc.Get(query, opts) if err != nil { return nil, err } s, ok := res.(interfaces.Spider) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *SpiderServiceDelegate) GetSpiderList(query bson.M, opts *mongo.FindOptions) (res []interfaces.Spider, err error) { list, err := svc.GetList(query, opts) if err != nil { return nil, err } for _, item := range list.GetModels() { s, ok := item.(interfaces.Spider) if !ok { return nil, errors.ErrorModelInvalidType } res = append(res, s) } return res, nil } func NewSpiderServiceDelegate() (svc2 interfaces.GrpcClientModelSpiderService, err error) { var opts []ModelBaseServiceDelegateOption // apply options opts = append(opts, WithBaseServiceModelId(interfaces.ModelIdSpider)) // base service baseSvc, err := NewBaseServiceDelegate(opts...) if err != nil { return nil, err } // service svc := &SpiderServiceDelegate{baseSvc} return svc, nil } ================================================ FILE: core/models/client/model_task_service.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskServiceDelegate struct { interfaces.GrpcClientModelBaseService } func (svc *TaskServiceDelegate) GetTaskById(id primitive.ObjectID) (t interfaces.Task, err error) { res, err := svc.GetById(id) if err != nil { return nil, err } s, ok := res.(interfaces.Task) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *TaskServiceDelegate) GetTask(query bson.M, opts *mongo.FindOptions) (t interfaces.Task, err error) { res, err := svc.Get(query, opts) if err != nil { return nil, err } s, ok := res.(interfaces.Task) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *TaskServiceDelegate) GetTaskList(query bson.M, opts *mongo.FindOptions) (res []interfaces.Task, err error) { list, err := svc.GetList(query, opts) if err != nil { return nil, err } for _, item := range list.GetModels() { s, ok := item.(interfaces.Task) if !ok { return nil, errors.ErrorModelInvalidType } res = append(res, s) } return res, nil } func NewTaskServiceDelegate() (svc2 interfaces.GrpcClientModelTaskService, err error) { var opts []ModelBaseServiceDelegateOption // apply options opts = append(opts, WithBaseServiceModelId(interfaces.ModelIdTask)) // base service baseSvc, err := NewBaseServiceDelegate(opts...) if err != nil { return nil, err } // service svc := &TaskServiceDelegate{baseSvc} return svc, nil } ================================================ FILE: core/models/client/model_task_stat_service.go ================================================ package client import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskStatServiceDelegate struct { interfaces.GrpcClientModelBaseService } func (svc *TaskStatServiceDelegate) GetTaskStatById(id primitive.ObjectID) (t interfaces.TaskStat, err error) { res, err := svc.GetById(id) if err != nil { return nil, err } s, ok := res.(interfaces.TaskStat) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *TaskStatServiceDelegate) GetTaskStat(query bson.M, opts *mongo.FindOptions) (t interfaces.TaskStat, err error) { res, err := svc.Get(query, opts) if err != nil { return nil, err } s, ok := res.(interfaces.TaskStat) if !ok { return nil, errors.ErrorModelInvalidType } return s, nil } func (svc *TaskStatServiceDelegate) GetTaskStatList(query bson.M, opts *mongo.FindOptions) (res []interfaces.TaskStat, err error) { list, err := svc.GetList(query, opts) if err != nil { return nil, err } for _, item := range list.GetModels() { s, ok := item.(interfaces.TaskStat) if !ok { return nil, errors.ErrorModelInvalidType } res = append(res, s) } return res, nil } func NewTaskStatServiceDelegate() (svc2 interfaces.GrpcClientModelTaskStatService, err error) { var opts []ModelBaseServiceDelegateOption // apply options opts = append(opts, WithBaseServiceModelId(interfaces.ModelIdTaskStat)) // base service baseSvc, err := NewBaseServiceDelegate(opts...) if err != nil { return nil, err } // service svc := &TaskStatServiceDelegate{baseSvc} return svc, nil } ================================================ FILE: core/models/client/options.go ================================================ package client import "github.com/crawlab-team/crawlab/core/interfaces" type ModelDelegateOption func(delegate interfaces.GrpcClientModelDelegate) func WithDelegateConfigPath(path string) ModelDelegateOption { return func(d interfaces.GrpcClientModelDelegate) { d.SetConfigPath(path) } } type ModelServiceDelegateOption func(delegate interfaces.GrpcClientModelService) func WithServiceConfigPath(path string) ModelServiceDelegateOption { return func(d interfaces.GrpcClientModelService) { d.SetConfigPath(path) } } type ModelBaseServiceDelegateOption func(delegate interfaces.GrpcClientModelBaseService) func WithBaseServiceModelId(id interfaces.ModelId) ModelBaseServiceDelegateOption { return func(d interfaces.GrpcClientModelBaseService) { d.SetModelId(id) } } func WithBaseServiceConfigPath(path string) ModelBaseServiceDelegateOption { return func(d interfaces.GrpcClientModelBaseService) { d.SetConfigPath(path) } } ================================================ FILE: core/models/common/index_service_v2.go ================================================ package common import ( models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" mongo2 "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func CreateIndexesV2() { // nodes mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.NodeV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"key": 1}}, // key {Keys: bson.M{"name": 1}}, // name {Keys: bson.M{"is_master": 1}}, // is_master {Keys: bson.M{"status": 1}}, // status {Keys: bson.M{"enabled": 1}}, // enabled {Keys: bson.M{"active": 1}}, // active }) // projects mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.ProjectV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, }) // spiders mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.SpiderV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, {Keys: bson.M{"type": 1}}, {Keys: bson.M{"col_id": 1}}, {Keys: bson.M{"project_id": 1}}, }) // tasks mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.TaskV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"spider_id": 1}}, {Keys: bson.M{"status": 1}}, {Keys: bson.M{"node_id": 1}}, {Keys: bson.M{"schedule_id": 1}}, {Keys: bson.M{"type": 1}}, {Keys: bson.M{"mode": 1}}, {Keys: bson.M{"priority": 1}}, {Keys: bson.M{"parent_id": 1}}, {Keys: bson.M{"has_sub": 1}}, {Keys: bson.M{"create_ts": -1}}, }) // task stats mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.TaskStatV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"create_ts": 1}}, }) // schedules mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.ScheduleV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, {Keys: bson.M{"spider_id": 1}}, {Keys: bson.M{"enabled": 1}}, }) // users mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.UserV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"username": 1}}, {Keys: bson.M{"role": 1}}, {Keys: bson.M{"email": 1}}, }) // settings mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.SettingV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.D{{"key", 1}}, Options: options.Index().SetUnique(true)}, }) // tokens mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.TokenV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, }) // variables mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.VariableV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"key": 1}}, }) // data sources mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DatabaseV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, }) // data collections mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DataCollectionV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.M{"name": 1}}, }) // roles mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.RoleV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.D{{"key", 1}}, Options: options.Index().SetUnique(true)}, }) // user role relations mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.UserRoleV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.D{{"user_id", 1}, {"role_id", 1}}, Options: options.Index().SetUnique(true)}, {Keys: bson.D{{"role_id", 1}, {"user_id", 1}}, Options: options.Index().SetUnique(true)}, }) // permissions mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.PermissionV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.D{{"key", 1}}, Options: options.Index().SetUnique(true)}, }) // role permission relations mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.RolePermissionV2{})).MustCreateIndexes([]mongo2.IndexModel{ {Keys: bson.D{{"role_id", 1}, {"permission_id", 1}}, Options: options.Index().SetUnique(true)}, {Keys: bson.D{{"permission_id", 1}, {"role_id", 1}}, Options: options.Index().SetUnique(true)}, }) // dependencies mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DependencyV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"type", 1}, {"node_id", 1}, {"name", 1}, }, Options: (&options.IndexOptions{}).SetUnique(true), }, }) // dependency settings mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DependencySettingV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"type", 1}, {"node_id", 1}, {"name", 1}, }, Options: (&options.IndexOptions{}).SetUnique(true), }, }) // dependency logs mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DependencyLogV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{{"task_id", 1}}, }, { Keys: bson.D{{"update_ts", 1}}, Options: (&options.IndexOptions{}).SetExpireAfterSeconds(60 * 60 * 24), }, }) // dependency tasks mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DependencyTaskV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"update_ts", 1}, }, Options: (&options.IndexOptions{}).SetExpireAfterSeconds(60 * 60 * 24), }, }) // metrics mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.MetricV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"created_ts", -1}, }, Options: (&options.IndexOptions{}).SetExpireAfterSeconds(60 * 60 * 24 * 30), }, { Keys: bson.D{ {"node_id", 1}, }, }, { Keys: bson.D{ {"type", 1}, }, }, }) // notification requests mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.NotificationRequestV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"created_ts", -1}, }, Options: (&options.IndexOptions{}).SetExpireAfterSeconds(60 * 60 * 24 * 7), }, { Keys: bson.D{ {"channel_id", 1}, }, }, { Keys: bson.D{ {"setting_id", 1}, }, }, { Keys: bson.D{ {"status", 1}, }, }, }) // databases mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DatabaseV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"data_source_id", 1}, }, }, }) // database metrics mongo.GetMongoCol(service.GetCollectionNameByInstance(models2.DatabaseMetricV2{})).MustCreateIndexes([]mongo2.IndexModel{ { Keys: bson.D{ {"created_ts", -1}, }, Options: (&options.IndexOptions{}).SetExpireAfterSeconds(60 * 60 * 24 * 30), }, { Keys: bson.D{ {"database_id", 1}, }, }, { Keys: bson.D{ {"type", 1}, }, }, }) } ================================================ FILE: core/models/config_spider/common.go ================================================ package config_spider import "github.com/crawlab-team/crawlab/core/entity" func GetAllFields(data entity.ConfigSpiderData) []entity.Field { var fields []entity.Field for _, stage := range data.Stages { fields = append(fields, stage.Fields...) } 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 "" } ================================================ FILE: core/models/config_spider/scrapy.go ================================================ package config_spider //import ( // "errors" // "fmt" // "github.com/crawlab-team/crawlab/core/constants" // "github.com/crawlab-team/crawlab/core/entity" // "github.com/crawlab-team/crawlab/core/models" // "github.com/crawlab-team/crawlab/core/utils" // "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) // } //} ================================================ FILE: core/models/delegate/base_test.go ================================================ package delegate_test import ( "context" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "testing" "time" ) func SetupTest(t *testing.T) { CleanupTest() t.Cleanup(CleanupTest) } func CleanupTest() { db := mongo.GetMongoDb("") names, _ := db.ListCollectionNames(context.Background(), bson.M{}) for _, n := range names { _, _ = db.Collection(n).DeleteMany(context.Background(), bson.M{}) } // avoid caching time.Sleep(200 * time.Millisecond) } ================================================ FILE: core/models/delegate/model.go ================================================ package delegate import ( "encoding/json" errors2 "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/event" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/errors" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "reflect" "time" ) func NewModelDelegate(doc interfaces.Model, args ...interface{}) interfaces.ModelDelegate { switch doc.(type) { case *models.Artifact: return newModelDelegate(interfaces.ModelIdArtifact, doc, args...) case *models.Tag: return newModelDelegate(interfaces.ModelIdTag, doc, args...) case *models.Node: return newModelDelegate(interfaces.ModelIdNode, doc, args...) case *models.Project: return newModelDelegate(interfaces.ModelIdProject, doc, args...) case *models.Spider: return newModelDelegate(interfaces.ModelIdSpider, doc, args...) case *models.Task: return newModelDelegate(interfaces.ModelIdTask, doc, args...) case *models.Job: return newModelDelegate(interfaces.ModelIdJob, doc, args...) case *models.Schedule: return newModelDelegate(interfaces.ModelIdSchedule, doc, args...) case *models.User: return newModelDelegate(interfaces.ModelIdUser, doc, args...) case *models.Setting: return newModelDelegate(interfaces.ModelIdSetting, doc, args...) case *models.Token: return newModelDelegate(interfaces.ModelIdToken, doc, args...) case *models.Variable: return newModelDelegate(interfaces.ModelIdVariable, doc, args...) case *models.TaskQueueItem: return newModelDelegate(interfaces.ModelIdTaskQueue, doc, args...) case *models.TaskStat: return newModelDelegate(interfaces.ModelIdTaskStat, doc, args...) case *models.SpiderStat: return newModelDelegate(interfaces.ModelIdSpiderStat, doc, args...) case *models.DataSource: return newModelDelegate(interfaces.ModelIdDataSource, doc, args...) case *models.DataCollection: return newModelDelegate(interfaces.ModelIdDataCollection, doc, args...) case *models.Result: return newModelDelegate(interfaces.ModelIdResult, doc, args...) case *models.Password: return newModelDelegate(interfaces.ModelIdPassword, doc, args...) case *models.ExtraValue: return newModelDelegate(interfaces.ModelIdExtraValue, doc, args...) case *models.Git: return newModelDelegate(interfaces.ModelIdGit, doc, args...) case *models.Role: return newModelDelegate(interfaces.ModelIdRole, doc, args...) case *models.UserRole: return newModelDelegate(interfaces.ModelIdUserRole, doc, args...) case *models.Permission: return newModelDelegate(interfaces.ModelIdPermission, doc, args...) case *models.RolePermission: return newModelDelegate(interfaces.ModelIdRolePermission, doc, args...) case *models.Environment: return newModelDelegate(interfaces.ModelIdEnvironment, doc, args...) case *models.DependencySetting: return newModelDelegate(interfaces.ModelIdDependencySetting, doc, args...) default: _ = trace.TraceError(errors2.ErrorModelInvalidType) return nil } } func newModelDelegate(id interfaces.ModelId, doc interfaces.Model, args ...interface{}) interfaces.ModelDelegate { // user u := utils.GetUserFromArgs(args...) // collection name colName := models.GetModelColName(id) // model delegate d := &ModelDelegate{ id: id, colName: colName, doc: doc, a: &models.Artifact{ Col: colName, }, u: u, } return d } type ModelDelegate struct { id interfaces.ModelId colName string doc interfaces.Model // doc to delegate cd bson.M // current doc od bson.M // original doc a interfaces.ModelArtifact // artifact u interfaces.User // user } // Add model func (d *ModelDelegate) Add() (err error) { return d.do(interfaces.ModelDelegateMethodAdd) } // Save model func (d *ModelDelegate) Save() (err error) { return d.do(interfaces.ModelDelegateMethodSave) } // Delete model func (d *ModelDelegate) Delete() (err error) { return d.do(interfaces.ModelDelegateMethodDelete) } // GetArtifact refresh artifact and return it func (d *ModelDelegate) GetArtifact() (res interfaces.ModelArtifact, err error) { if err := d.do(interfaces.ModelDelegateMethodGetArtifact); err != nil { return nil, err } return d.a, nil } // Refresh model func (d *ModelDelegate) Refresh() (err error) { return d.refresh() } // GetModel return model func (d *ModelDelegate) GetModel() (res interfaces.Model) { return d.doc } func (d *ModelDelegate) ToBytes(m interface{}) (bytes []byte, err error) { if m != nil { return utils.JsonToBytes(m) } return json.Marshal(d.doc) } // do action given the model delegate method func (d *ModelDelegate) do(method interfaces.ModelDelegateMethod) (err error) { switch method { case interfaces.ModelDelegateMethodAdd: err = d.add() case interfaces.ModelDelegateMethodSave: err = d.save() case interfaces.ModelDelegateMethodDelete: err = d.delete() case interfaces.ModelDelegateMethodGetArtifact, interfaces.ModelDelegateMethodRefresh: err = d.refresh() default: return trace.TraceError(errors2.ErrorModelInvalidType) } if err != nil { return err } // trigger event eventName := GetEventName(d, method) go event.SendEvent(eventName, d.doc) return nil } // add model func (d *ModelDelegate) add() (err error) { if d.doc == nil { return trace.TraceError(errors.ErrMissingValue) } if d.doc.GetId().IsZero() { d.doc.SetId(primitive.NewObjectID()) } col := mongo.GetMongoCol(d.colName) if _, err = col.Insert(d.doc); err != nil { return trace.TraceError(err) } if err := d.upsertArtifact(); err != nil { return trace.TraceError(err) } return d.refresh() } // save model func (d *ModelDelegate) save() (err error) { // validate if d.doc == nil || d.doc.GetId().IsZero() { return trace.TraceError(errors.ErrMissingValue) } // collection col := mongo.GetMongoCol(d.colName) // current doc docData, err := bson.Marshal(d.doc) if err != nil { trace.PrintError(err) } else { if err := bson.Unmarshal(docData, &d.cd); err != nil { trace.PrintError(err) } } // original doc if err := col.FindId(d.doc.GetId()).One(&d.od); err != nil { trace.PrintError(err) } // replace if err := col.ReplaceId(d.doc.GetId(), d.doc); err != nil { return trace.TraceError(err) } // upsert artifact if err := d.upsertArtifact(); err != nil { return trace.TraceError(err) } return d.refresh() } // delete model func (d *ModelDelegate) delete() (err error) { if d.doc.GetId().IsZero() { return trace.TraceError(errors2.ErrorModelMissingId) } col := mongo.GetMongoCol(d.colName) if err := col.FindId(d.doc.GetId()).One(d.doc); err != nil { return trace.TraceError(err) } if err := col.DeleteId(d.doc.GetId()); err != nil { return trace.TraceError(err) } return d.deleteArtifact() } // refresh model and artifact func (d *ModelDelegate) refresh() (err error) { if d.doc.GetId().IsZero() { return trace.TraceError(errors2.ErrorModelMissingId) } col := mongo.GetMongoCol(d.colName) fr := col.FindId(d.doc.GetId()) if err := fr.One(d.doc); err != nil { return trace.TraceError(err) } return d.refreshArtifact() } // refresh artifact func (d *ModelDelegate) refreshArtifact() (err error) { if d.doc.GetId().IsZero() { return trace.TraceError(errors2.ErrorModelMissingId) } col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) if err := col.FindId(d.doc.GetId()).One(d.a); err != nil { return trace.TraceError(err) } return nil } // upsertArtifact func (d *ModelDelegate) upsertArtifact() (err error) { // skip if d._skip() { return nil } // validate id if d.doc.GetId().IsZero() { return trace.TraceError(errors.ErrMissingValue) } // mongo collection col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) // assign id to artifact d.a.SetId(d.doc.GetId()) // attempt to find artifact if err := col.FindId(d.doc.GetId()).One(d.a); err != nil { if err == mongo2.ErrNoDocuments { // new artifact d.a.GetSys().SetCreateTs(time.Now()) d.a.GetSys().SetUpdateTs(time.Now()) if d.u != nil && !reflect.ValueOf(d.u).IsZero() { d.a.GetSys().SetCreateUid(d.u.GetId()) d.a.GetSys().SetUpdateUid(d.u.GetId()) } _, err = col.Insert(d.a) if err != nil { return trace.TraceError(err) } return nil } else { // error return trace.TraceError(err) } } // existing artifact d.a.GetSys().SetUpdateTs(time.Now()) if d.u != nil { d.a.GetSys().SetUpdateUid(d.u.GetId()) } // save new artifact return col.ReplaceId(d.a.GetId(), d.a) } // deleteArtifact func (d *ModelDelegate) deleteArtifact() (err error) { // skip if d._skip() { return nil } if d.doc.GetId().IsZero() { return trace.TraceError(errors.ErrMissingValue) } col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) d.a.SetId(d.doc.GetId()) d.a.SetObj(d.doc) d.a.SetDel(true) d.a.GetSys().SetDeleteTs(time.Now()) if d.u != nil { d.a.GetSys().SetDeleteUid(d.u.GetId()) } return col.ReplaceId(d.doc.GetId(), d.a) } func (d *ModelDelegate) hasChange() (ok bool) { return !utils.BsonMEqual(d.cd, d.od) } func (d *ModelDelegate) _skip() (ok bool) { switch d.id { case interfaces.ModelIdArtifact, interfaces.ModelIdTaskQueue, interfaces.ModelIdTaskStat, interfaces.ModelIdSpiderStat, interfaces.ModelIdResult, interfaces.ModelIdPassword: return true default: return false } } ================================================ FILE: core/models/delegate/model_node.go ================================================ package delegate import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type ModelNodeDelegate struct { n interfaces.Node interfaces.ModelDelegate } func (d *ModelNodeDelegate) UpdateStatus(active bool, activeTs *time.Time, status string) (err error) { d.n.SetActive(active) if activeTs != nil { d.n.SetActiveTs(*activeTs) } d.n.SetStatus(status) return d.Save() } func (d *ModelNodeDelegate) UpdateStatusOnline() (err error) { now := time.Now() return d.UpdateStatus(true, &now, constants.NodeStatusOnline) } func (d *ModelNodeDelegate) UpdateStatusOffline() (err error) { return d.UpdateStatus(false, nil, constants.NodeStatusOffline) } func NewModelNodeDelegate(n interfaces.Node) interfaces.ModelNodeDelegate { return &ModelNodeDelegate{ n: n, ModelDelegate: NewModelDelegate(n), } } ================================================ FILE: core/models/delegate/model_node_test.go ================================================ package delegate_test import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "github.com/stretchr/testify/require" "testing" ) func TestNode_Add(t *testing.T) { SetupTest(t) n := &models2.Node{} err := delegate.NewModelDelegate(n).Add() require.Nil(t, err) require.NotNil(t, n.Id) // validate artifact a, err := delegate.NewModelDelegate(n).GetArtifact() require.Nil(t, err) require.Equal(t, n.Id, a.GetId()) require.NotNil(t, a.GetSys().GetCreateTs()) require.NotNil(t, a.GetSys().GetUpdateTs()) } func TestNode_Save(t *testing.T) { SetupTest(t) n := &models2.Node{} err := delegate.NewModelDelegate(n).Add() name := "test_node" n.Name = name err = delegate.NewModelDelegate(n).Save() require.Nil(t, err) err = mongo.GetMongoCol(interfaces.ModelColNameNode).FindId(n.Id).One(&n) require.Nil(t, err) require.Equal(t, name, n.Name) } func TestNode_Delete(t *testing.T) { SetupTest(t) n := &models2.Node{ Name: "test_node", } err := delegate.NewModelDelegate(n).Add() require.Nil(t, err) err = delegate.NewModelDelegate(n).Delete() require.Nil(t, err) var a models2.Artifact col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) err = col.FindId(n.Id).One(&a) require.Nil(t, err) require.NotNil(t, a.Obj) require.True(t, a.Del) } ================================================ FILE: core/models/delegate/model_role_test.go ================================================ package delegate_test import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "github.com/stretchr/testify/require" "testing" ) func TestRole_Add(t *testing.T) { SetupTest(t) p := &models2.Role{} err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) require.NotNil(t, p.Id) a, err := delegate.NewModelDelegate(p).GetArtifact() require.Nil(t, err) require.Equal(t, p.Id, a.GetId()) require.NotNil(t, a.GetSys().GetCreateTs()) require.NotNil(t, a.GetSys().GetUpdateTs()) } func TestRole_Save(t *testing.T) { SetupTest(t) p := &models2.Role{} err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) name := "test_role" p.Name = name err = delegate.NewModelDelegate(p).Save() require.Nil(t, err) err = mongo.GetMongoCol(interfaces.ModelColNameRole).FindId(p.Id).One(&p) require.Nil(t, err) require.Equal(t, name, p.Name) } func TestRole_Delete(t *testing.T) { SetupTest(t) p := &models2.Role{ Name: "test_role", } err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) err = delegate.NewModelDelegate(p).Delete() require.Nil(t, err) var a models2.Artifact col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) err = col.FindId(p.Id).One(&a) require.Nil(t, err) require.NotNil(t, a.Obj) require.True(t, a.Del) } ================================================ FILE: core/models/delegate/model_test.go ================================================ package delegate_test import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "github.com/stretchr/testify/require" "testing" ) func TestProject_Add(t *testing.T) { SetupTest(t) p := &models2.Project{} err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) require.NotNil(t, p.Id) a, err := delegate.NewModelDelegate(p).GetArtifact() require.Nil(t, err) require.Equal(t, p.Id, a.GetId()) require.NotNil(t, a.GetSys().GetCreateTs()) require.NotNil(t, a.GetSys().GetUpdateTs()) } func TestProject_Save(t *testing.T) { SetupTest(t) p := &models2.Project{} err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) name := "test_project" p.Name = name err = delegate.NewModelDelegate(p).Save() require.Nil(t, err) err = mongo.GetMongoCol(interfaces.ModelColNameProject).FindId(p.Id).One(&p) require.Nil(t, err) require.Equal(t, name, p.Name) } func TestProject_Delete(t *testing.T) { SetupTest(t) p := &models2.Project{ Name: "test_project", } err := delegate.NewModelDelegate(p).Add() require.Nil(t, err) err = delegate.NewModelDelegate(p).Delete() require.Nil(t, err) var a models2.Artifact col := mongo.GetMongoCol(interfaces.ModelColNameArtifact) err = col.FindId(p.Id).One(&a) require.Nil(t, err) require.NotNil(t, a.Obj) require.True(t, a.Del) } ================================================ FILE: core/models/delegate/utils_event.go ================================================ package delegate import ( "fmt" "github.com/crawlab-team/crawlab/core/interfaces" ) func GetEventName(d *ModelDelegate, method interfaces.ModelDelegateMethod) (eventName string) { return getEventName(d, method) } func getEventName(d *ModelDelegate, method interfaces.ModelDelegateMethod) (eventName string) { if method == interfaces.ModelDelegateMethodSave { hasChange := d.hasChange() if hasChange { method = interfaces.ModelDelegateMethodChange } } return fmt.Sprintf("model:%s:%s", d.colName, method) } ================================================ FILE: core/models/models/artifact.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Artifact struct { Id primitive.ObjectID `bson:"_id" json:"_id"` Col string `bson:"_col" json:"_col"` Del bool `bson:"_del" json:"_del"` TagIds []primitive.ObjectID `bson:"_tid" json:"_tid"` Sys *ArtifactSys `bson:"_sys" json:"_sys"` Obj interface{} `bson:"_obj" json:"_obj"` } func (a *Artifact) GetId() (id primitive.ObjectID) { return a.Id } func (a *Artifact) SetId(id primitive.ObjectID) { a.Id = id } func (a *Artifact) GetSys() (sys interfaces.ModelArtifactSys) { if a.Sys == nil { a.Sys = &ArtifactSys{} } return a.Sys } func (a *Artifact) GetTagIds() (ids []primitive.ObjectID) { return a.TagIds } func (a *Artifact) SetTagIds(ids []primitive.ObjectID) { a.TagIds = ids } func (a *Artifact) SetObj(obj interfaces.Model) { a.Obj = obj } func (a *Artifact) SetDel(del bool) { a.Del = del } type ArtifactList []Artifact func (l *ArtifactList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/artifact_sys.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type ArtifactSys struct { CreateTs time.Time `json:"create_ts" bson:"create_ts"` CreateUid primitive.ObjectID `json:"create_uid" bson:"create_uid"` UpdateTs time.Time `json:"update_ts" bson:"update_ts"` UpdateUid primitive.ObjectID `json:"update_uid" bson:"update_uid"` DeleteTs time.Time `json:"delete_ts" bson:"delete_ts"` DeleteUid primitive.ObjectID `json:"delete_uid" bson:"delete_uid"` } func (sys *ArtifactSys) GetCreateTs() time.Time { return sys.CreateTs } func (sys *ArtifactSys) SetCreateTs(ts time.Time) { sys.CreateTs = ts } func (sys *ArtifactSys) GetUpdateTs() time.Time { return sys.UpdateTs } func (sys *ArtifactSys) SetUpdateTs(ts time.Time) { sys.UpdateTs = ts } func (sys *ArtifactSys) GetDeleteTs() time.Time { return sys.DeleteTs } func (sys *ArtifactSys) SetDeleteTs(ts time.Time) { sys.DeleteTs = ts } func (sys *ArtifactSys) GetCreateUid() primitive.ObjectID { return sys.CreateUid } func (sys *ArtifactSys) SetCreateUid(id primitive.ObjectID) { sys.CreateUid = id } func (sys *ArtifactSys) GetUpdateUid() primitive.ObjectID { return sys.UpdateUid } func (sys *ArtifactSys) SetUpdateUid(id primitive.ObjectID) { sys.UpdateUid = id } func (sys *ArtifactSys) GetDeleteUid() primitive.ObjectID { return sys.DeleteUid } func (sys *ArtifactSys) SetDeleteUid(id primitive.ObjectID) { sys.DeleteUid = id } ================================================ FILE: core/models/models/base.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type BaseModel struct { Id primitive.ObjectID `json:"_id" bson:"_id"` } func (d *BaseModel) GetId() (id primitive.ObjectID) { return d.Id } ================================================ FILE: core/models/models/data_collection.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type DataCollection struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Fields []entity.DataField `json:"fields" bson:"fields"` Dedup struct { Enabled bool `json:"enabled" bson:"enabled"` Keys []string `json:"keys" bson:"keys"` Type string `json:"type" bson:"type"` } `json:"dedup" bson:"dedup"` } func (dc *DataCollection) GetId() (id primitive.ObjectID) { return dc.Id } func (dc *DataCollection) SetId(id primitive.ObjectID) { dc.Id = id } type DataCollectionList []DataCollection func (l *DataCollectionList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/data_source.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type DataSource struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Type string `json:"type" bson:"type"` Description string `json:"description" bson:"description"` Host string `json:"host" bson:"host"` Port int `json:"port" bson:"port"` Url string `json:"url" bson:"url"` Hosts []string `json:"hosts" bson:"hosts"` Database string `json:"database" bson:"database"` Username string `json:"username" bson:"username"` Password string `json:"password,omitempty" bson:"-"` ConnectType string `json:"connect_type" bson:"connect_type"` Status string `json:"status" bson:"status"` Error string `json:"error" bson:"error"` Extra map[string]string `json:"extra,omitempty" bson:"extra,omitempty"` } func (ds *DataSource) GetId() (id primitive.ObjectID) { return ds.Id } func (ds *DataSource) SetId(id primitive.ObjectID) { ds.Id = id } type DataSourceList []DataSource func (l *DataSourceList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/dependency_setting.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type DependencySetting struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Enabled bool `json:"enabled" bson:"enabled"` Cmd string `json:"cmd" bson:"cmd"` Proxy string `json:"proxy" bson:"proxy"` LastUpdateTs time.Time `json:"last_update_ts" bson:"last_update_ts"` } func (j *DependencySetting) GetId() (id primitive.ObjectID) { return j.Id } func (j *DependencySetting) SetId(id primitive.ObjectID) { j.Id = id } type DependencySettingList []DependencySetting func (l *DependencySettingList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/environment.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Environment struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Value string `json:"value" bson:"value"` } func (e *Environment) GetId() (id primitive.ObjectID) { return e.Id } func (e *Environment) SetId(id primitive.ObjectID) { e.Id = id } func (e *Environment) GetKey() (key string) { return e.Key } func (e *Environment) SetKey(key string) { e.Key = key } func (e *Environment) GetValue() (value string) { return e.Value } func (e *Environment) SetValue(value string) { e.Value = value } type EnvironmentList []Environment func (l *EnvironmentList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/extra_value.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type ExtraValue struct { Id primitive.ObjectID `json:"_id" bson:"_id"` ObjectId primitive.ObjectID `json:"oid" bson:"oid"` Model string `json:"model" bson:"m"` Type string `json:"type" bson:"t"` Value interface{} `json:"value" bson:"v"` } func (ev *ExtraValue) GetId() (id primitive.ObjectID) { return ev.Id } func (ev *ExtraValue) SetId(id primitive.ObjectID) { ev.Id = id } func (ev *ExtraValue) GetValue() (v interface{}) { return ev.Value } func (ev *ExtraValue) SetValue(v interface{}) { ev.Value = v } func (ev *ExtraValue) GetObjectId() (oid primitive.ObjectID) { return ev.ObjectId } func (ev *ExtraValue) SetObjectId(oid primitive.ObjectID) { ev.ObjectId = oid } func (ev *ExtraValue) GetModel() (m string) { return ev.Model } func (ev *ExtraValue) SetModel(m string) { ev.Model = m } func (ev *ExtraValue) GetType() (t string) { return ev.Type } func (ev *ExtraValue) SetType(t string) { ev.Type = t } type ExtraValueList []ExtraValue func (l *ExtraValueList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/git.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Git struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Url string `json:"url" bson:"url"` AuthType string `json:"auth_type" bson:"auth_type"` Username string `json:"username" bson:"username"` Password string `json:"password" bson:"password"` CurrentBranch string `json:"current_branch" bson:"current_branch"` AutoPull bool `json:"auto_pull" bson:"auto_pull"` } func (g *Git) GetId() (id primitive.ObjectID) { return g.Id } func (g *Git) SetId(id primitive.ObjectID) { g.Id = id } func (g *Git) GetUrl() (url string) { return g.Url } func (g *Git) SetUrl(url string) { g.Url = url } func (g *Git) GetAuthType() (authType string) { return g.AuthType } func (g *Git) SetAuthType(authType string) { g.AuthType = authType } func (g *Git) GetUsername() (username string) { return g.Username } func (g *Git) SetUsername(username string) { g.Username = username } func (g *Git) GetPassword() (password string) { return g.Password } func (g *Git) SetPassword(password string) { g.Password = password } func (g *Git) GetCurrentBranch() (currentBranch string) { return g.CurrentBranch } func (g *Git) SetCurrentBranch(currentBranch string) { g.CurrentBranch = currentBranch } func (g *Git) GetAutoPull() (autoPull bool) { return g.AutoPull } func (g *Git) SetAutoPull(autoPull bool) { g.AutoPull = autoPull } type GitList []Git func (l *GitList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/job.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Job struct { Id primitive.ObjectID `bson:"_id" json:"_id"` TaskId primitive.ObjectID `bson:"task_id" json:"task_id"` } func (j *Job) GetId() (id primitive.ObjectID) { return j.Id } func (j *Job) SetId(id primitive.ObjectID) { j.Id = id } type JobList []Job func (l *JobList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/node.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type Node struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` 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"` IsMaster bool `json:"is_master" bson:"is_master"` Status string `json:"status" bson:"status"` Enabled bool `json:"enabled" bson:"enabled"` Active bool `json:"active" bson:"active"` ActiveTs time.Time `json:"active_ts" bson:"active_ts"` AvailableRunners int `json:"available_runners" bson:"available_runners"` MaxRunners int `json:"max_runners" bson:"max_runners"` } func (n *Node) GetId() (id primitive.ObjectID) { return n.Id } func (n *Node) SetId(id primitive.ObjectID) { n.Id = id } func (n *Node) GetName() (name string) { return n.Name } func (n *Node) SetName(name string) { n.Name = name } func (n *Node) GetDescription() (description string) { return n.Description } func (n *Node) SetDescription(description string) { n.Description = description } func (n *Node) GetKey() (key string) { return n.Key } func (n *Node) GetIsMaster() (ok bool) { return n.IsMaster } func (n *Node) GetActive() (active bool) { return n.Active } func (n *Node) SetActive(active bool) { n.Active = active } func (n *Node) SetActiveTs(activeTs time.Time) { n.ActiveTs = activeTs } func (n *Node) GetStatus() (status string) { return n.Status } func (n *Node) SetStatus(status string) { n.Status = status } func (n *Node) GetEnabled() (enabled bool) { return n.Enabled } func (n *Node) SetEnabled(enabled bool) { n.Enabled = enabled } func (n *Node) GetAvailableRunners() (runners int) { return n.AvailableRunners } func (n *Node) SetAvailableRunners(runners int) { n.AvailableRunners = runners } func (n *Node) GetMaxRunners() (runners int) { return n.MaxRunners } func (n *Node) SetMaxRunners(runners int) { n.MaxRunners = runners } func (n *Node) IncrementAvailableRunners() { n.AvailableRunners++ } func (n *Node) DecrementAvailableRunners() { n.AvailableRunners-- } type NodeList []Node func (l *NodeList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/password.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Password struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Password string `json:"password" bson:"p"` } func (p *Password) GetId() (id primitive.ObjectID) { return p.Id } func (p *Password) SetId(id primitive.ObjectID) { p.Id = id } type PasswordList []Password func (l *PasswordList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/permission.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Permission struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Type string `json:"type" bson:"type"` Target []string `json:"target" bson:"target"` Allow []string `json:"allow" bson:"allow"` Deny []string `json:"deny" bson:"deny"` } func (p *Permission) GetId() (id primitive.ObjectID) { return p.Id } func (p *Permission) SetId(id primitive.ObjectID) { p.Id = id } func (p *Permission) GetKey() (key string) { return p.Key } func (p *Permission) SetKey(key string) { p.Key = key } func (p *Permission) GetName() (name string) { return p.Name } func (p *Permission) SetName(name string) { p.Name = name } func (p *Permission) GetDescription() (description string) { return p.Description } func (p *Permission) SetDescription(description string) { p.Description = description } func (p *Permission) GetType() (t string) { return p.Type } func (p *Permission) SetType(t string) { p.Type = t } func (p *Permission) GetTarget() (target []string) { return p.Target } func (p *Permission) SetTarget(target []string) { p.Target = target } func (p *Permission) GetAllow() (include []string) { return p.Allow } func (p *Permission) SetAllow(include []string) { p.Allow = include } func (p *Permission) GetDeny() (exclude []string) { return p.Deny } func (p *Permission) SetDeny(exclude []string) { p.Deny = exclude } type PermissionList []Permission func (l *PermissionList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/project.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Project struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Spiders int `json:"spiders" bson:"-"` } func (p *Project) GetId() (id primitive.ObjectID) { return p.Id } func (p *Project) SetId(id primitive.ObjectID) { p.Id = id } func (p *Project) GetName() (name string) { return p.Name } func (p *Project) SetName(name string) { p.Name = name } func (p *Project) GetDescription() (description string) { return p.Description } func (p *Project) SetDescription(description string) { p.Description = description } type ProjectList []Project func (l *ProjectList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/result.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type Result bson.M func (r *Result) GetId() (id primitive.ObjectID) { res, ok := r.Value()["_id"] if ok { id, ok = res.(primitive.ObjectID) if ok { return id } } return id } func (r *Result) SetId(id primitive.ObjectID) { (*r)["_id"] = id } func (r *Result) Value() map[string]interface{} { return *r } func (r *Result) SetValue(key string, value interface{}) { (*r)[key] = value } func (r *Result) GetValue(key string) (value interface{}) { return (*r)[key] } func (r *Result) GetTaskId() (id primitive.ObjectID) { res := r.GetValue(constants.TaskKey) if res == nil { return id } id, _ = res.(primitive.ObjectID) return id } func (r *Result) SetTaskId(id primitive.ObjectID) { r.SetValue(constants.TaskKey, id) } type ResultList []Result func (l *ResultList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/role.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Role struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` } func (r *Role) GetId() (id primitive.ObjectID) { return r.Id } func (r *Role) SetId(id primitive.ObjectID) { r.Id = id } func (r *Role) GetKey() (key string) { return r.Key } func (r *Role) SetKey(key string) { r.Key = key } func (r *Role) GetName() (name string) { return r.Name } func (r *Role) SetName(name string) { r.Name = name } func (r *Role) GetDescription() (description string) { return r.Description } func (r *Role) SetDescription(description string) { r.Description = description } type RoleList []Role func (l *RoleList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/role_permission.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type RolePermission struct { Id primitive.ObjectID `json:"_id" bson:"_id"` RoleId primitive.ObjectID `json:"role_id" bson:"role_id"` PermissionId primitive.ObjectID `json:"permission_id" bson:"permission_id"` } func (ur *RolePermission) GetId() (id primitive.ObjectID) { return ur.Id } func (ur *RolePermission) SetId(id primitive.ObjectID) { ur.Id = id } type RolePermissionList []RolePermission func (l *RolePermissionList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/schedule.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson/primitive" ) type Schedule struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` SpiderId primitive.ObjectID `json:"spider_id" bson:"spider_id"` Cron string `json:"cron" bson:"cron"` EntryId cron.EntryID `json:"entry_id" bson:"entry_id"` Cmd string `json:"cmd" bson:"cmd"` Param string `json:"param" bson:"param"` Mode string `json:"mode" bson:"mode"` NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` Priority int `json:"priority" bson:"priority"` Enabled bool `json:"enabled" bson:"enabled"` UserId primitive.ObjectID `json:"user_id" bson:"user_id"` } func (s *Schedule) GetId() (id primitive.ObjectID) { return s.Id } func (s *Schedule) SetId(id primitive.ObjectID) { s.Id = id } func (s *Schedule) GetEnabled() (enabled bool) { return s.Enabled } func (s *Schedule) SetEnabled(enabled bool) { s.Enabled = enabled } func (s *Schedule) GetEntryId() (id cron.EntryID) { return s.EntryId } func (s *Schedule) SetEntryId(id cron.EntryID) { s.EntryId = id } func (s *Schedule) GetCron() (c string) { return s.Cron } func (s *Schedule) SetCron(c string) { s.Cron = c } func (s *Schedule) GetSpiderId() (id primitive.ObjectID) { return s.SpiderId } func (s *Schedule) SetSpiderId(id primitive.ObjectID) { s.SpiderId = id } func (s *Schedule) GetMode() (mode string) { return s.Mode } func (s *Schedule) SetMode(mode string) { s.Mode = mode } func (s *Schedule) GetNodeIds() (ids []primitive.ObjectID) { return s.NodeIds } func (s *Schedule) SetNodeIds(ids []primitive.ObjectID) { s.NodeIds = ids } func (s *Schedule) GetCmd() (cmd string) { return s.Cmd } func (s *Schedule) SetCmd(cmd string) { s.Cmd = cmd } func (s *Schedule) GetParam() (param string) { return s.Param } func (s *Schedule) SetParam(param string) { s.Param = param } func (s *Schedule) GetPriority() (p int) { return s.Priority } func (s *Schedule) SetPriority(p int) { s.Priority = p } type ScheduleList []Schedule func (l *ScheduleList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/setting.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type Setting struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Value bson.M `json:"value" bson:"value"` } func (s *Setting) GetId() (id primitive.ObjectID) { return s.Id } func (s *Setting) SetId(id primitive.ObjectID) { s.Id = id } type SettingList []Setting func (l *SettingList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/spider.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Env struct { Name string `json:"name" bson:"name"` Value string `json:"value" bson:"value"` } type Spider struct { Id primitive.ObjectID `json:"_id" bson:"_id"` // spider id Name string `json:"name" bson:"name"` // spider name Type string `json:"type" bson:"type"` // spider type ColId primitive.ObjectID `json:"col_id" bson:"col_id"` // data collection id ColName string `json:"col_name,omitempty" bson:"-"` // data collection name DataSourceId primitive.ObjectID `json:"data_source_id" bson:"data_source_id"` // data source id DataSource *DataSource `json:"data_source,omitempty" bson:"-"` // data source Description string `json:"description" bson:"description"` // description ProjectId primitive.ObjectID `json:"project_id" bson:"project_id"` // Project.Id Mode string `json:"mode" bson:"mode"` // default Task.Mode NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` // default Task.NodeIds Stat *SpiderStat `json:"stat,omitempty" bson:"-"` // execution Cmd string `json:"cmd" bson:"cmd"` // execute command Param string `json:"param" bson:"param"` // default task param Priority int `json:"priority" bson:"priority"` AutoInstall bool `json:"auto_install" bson:"auto_install"` // settings IncrementalSync bool `json:"incremental_sync" bson:"incremental_sync"` // whether to incrementally sync files } func (s *Spider) GetId() (id primitive.ObjectID) { return s.Id } func (s *Spider) SetId(id primitive.ObjectID) { s.Id = id } func (s *Spider) GetName() (name string) { return s.Name } func (s *Spider) SetName(name string) { s.Name = name } func (s *Spider) GetDescription() (description string) { return s.Description } func (s *Spider) SetDescription(description string) { s.Description = description } func (s *Spider) GetType() (ty string) { return s.Type } func (s *Spider) GetMode() (mode string) { return s.Mode } func (s *Spider) SetMode(mode string) { s.Mode = mode } func (s *Spider) GetNodeIds() (ids []primitive.ObjectID) { return s.NodeIds } func (s *Spider) SetNodeIds(ids []primitive.ObjectID) { s.NodeIds = ids } func (s *Spider) GetCmd() (cmd string) { return s.Cmd } func (s *Spider) SetCmd(cmd string) { s.Cmd = cmd } func (s *Spider) GetParam() (param string) { return s.Param } func (s *Spider) SetParam(param string) { s.Param = param } func (s *Spider) GetPriority() (p int) { return s.Priority } func (s *Spider) SetPriority(p int) { s.Priority = p } func (s *Spider) GetColId() (id primitive.ObjectID) { return s.ColId } func (s *Spider) SetColId(id primitive.ObjectID) { s.ColId = id } func (s *Spider) GetIncrementalSync() (incrementalSync bool) { return s.IncrementalSync } func (s *Spider) SetIncrementalSync(incrementalSync bool) { s.IncrementalSync = incrementalSync } func (s *Spider) GetAutoInstall() (autoInstall bool) { return s.AutoInstall } func (s *Spider) SetAutoInstall(autoInstall bool) { s.AutoInstall = autoInstall } type SpiderList []Spider func (l *SpiderList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/spider_stat.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type SpiderStat struct { Id primitive.ObjectID `json:"_id" bson:"_id"` LastTaskId primitive.ObjectID `json:"last_task_id" bson:"last_task_id,omitempty"` LastTask *Task `json:"last_task,omitempty" bson:"-"` Tasks int `json:"tasks" bson:"tasks"` Results int `json:"results" bson:"results"` WaitDuration int64 `json:"wait_duration" bson:"wait_duration,omitempty"` // in second RuntimeDuration int64 `json:"runtime_duration" bson:"runtime_duration,omitempty"` // in second TotalDuration int64 `json:"total_duration" bson:"total_duration,omitempty"` // in second AverageWaitDuration int64 `json:"average_wait_duration" bson:"-"` // in second AverageRuntimeDuration int64 `json:"average_runtime_duration" bson:"-"` // in second AverageTotalDuration int64 `json:"average_total_duration" bson:"-"` // in second } func (s *SpiderStat) GetId() (id primitive.ObjectID) { return s.Id } func (s *SpiderStat) SetId(id primitive.ObjectID) { s.Id = id } type SpiderStatList []SpiderStat func (l *SpiderStatList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/tag.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Tag struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Color string `json:"color" bson:"color"` Description string `json:"description" bson:"description"` Col string `json:"col" bson:"col"` } func (t *Tag) GetId() (id primitive.ObjectID) { return t.Id } func (t *Tag) SetId(id primitive.ObjectID) { t.Id = id } func (t *Tag) GetName() (res string) { return t.Name } func (t *Tag) GetColor() (res string) { return t.Color } func (t *Tag) SetCol(col string) { t.Col = col } type TagList []Tag func (l *TagList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/task.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type Task struct { Id primitive.ObjectID `json:"_id" bson:"_id"` SpiderId primitive.ObjectID `json:"spider_id" bson:"spider_id"` Status string `json:"status" bson:"status"` NodeId primitive.ObjectID `json:"node_id" bson:"node_id"` Cmd string `json:"cmd" bson:"cmd"` Param string `json:"param" bson:"param"` Error string `json:"error" bson:"error"` Pid int `json:"pid" bson:"pid"` ScheduleId primitive.ObjectID `json:"schedule_id" bson:"schedule_id"` // Schedule.Id Type string `json:"type" bson:"type"` Mode string `json:"mode" bson:"mode"` // running mode of Task NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` // list of Node.Id ParentId primitive.ObjectID `json:"parent_id" bson:"parent_id"` // parent Task.Id if it'Spider a sub-task Priority int `json:"priority" bson:"priority"` Stat *TaskStat `json:"stat,omitempty" bson:"-"` HasSub bool `json:"has_sub" json:"has_sub"` // whether to have sub-tasks SubTasks []Task `json:"sub_tasks,omitempty" bson:"-"` Spider *Spider `json:"spider,omitempty" bson:"-"` UserId primitive.ObjectID `json:"-" bson:"-"` CreateTs time.Time `json:"create_ts" bson:"create_ts"` } func (t *Task) GetId() (id primitive.ObjectID) { return t.Id } func (t *Task) SetId(id primitive.ObjectID) { t.Id = id } func (t *Task) GetNodeId() (id primitive.ObjectID) { return t.NodeId } func (t *Task) SetNodeId(id primitive.ObjectID) { t.NodeId = id } func (t *Task) GetNodeIds() (ids []primitive.ObjectID) { return t.NodeIds } func (t *Task) GetStatus() (status string) { return t.Status } func (t *Task) SetStatus(status string) { t.Status = status } func (t *Task) GetError() (error string) { return t.Error } func (t *Task) SetError(error string) { t.Error = error } func (t *Task) GetPid() (pid int) { return t.Pid } func (t *Task) SetPid(pid int) { t.Pid = pid } func (t *Task) GetSpiderId() (id primitive.ObjectID) { return t.SpiderId } func (t *Task) GetType() (ty string) { return t.Type } func (t *Task) GetCmd() (cmd string) { return t.Cmd } func (t *Task) GetParam() (param string) { return t.Param } func (t *Task) GetPriority() (p int) { return t.Priority } func (t *Task) GetUserId() (id primitive.ObjectID) { return t.UserId } func (t *Task) SetUserId(id primitive.ObjectID) { t.UserId = id } type TaskList []Task func (l *TaskList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } 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"` } ================================================ FILE: core/models/models/task_queue_item.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskQueueItem struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Priority int `json:"p" bson:"p"` NodeId primitive.ObjectID `json:"nid,omitempty" bson:"nid,omitempty"` } func (t *TaskQueueItem) GetId() (id primitive.ObjectID) { return t.Id } func (t *TaskQueueItem) SetId(id primitive.ObjectID) { t.Id = id } type TaskQueueItemList []TaskQueueItem func (l *TaskQueueItemList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/task_stat.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type TaskStat struct { Id primitive.ObjectID `json:"_id" bson:"_id"` CreateTs time.Time `json:"create_ts" bson:"create_ts,omitempty"` StartTs time.Time `json:"start_ts" bson:"start_ts,omitempty"` EndTs time.Time `json:"end_ts" bson:"end_ts,omitempty"` WaitDuration int64 `json:"wait_duration" bson:"wait_duration,omitempty"` // in millisecond RuntimeDuration int64 `json:"runtime_duration" bson:"runtime_duration,omitempty"` // in millisecond TotalDuration int64 `json:"total_duration" bson:"total_duration,omitempty"` // in millisecond ResultCount int64 `json:"result_count" bson:"result_count"` ErrorLogCount int64 `json:"error_log_count" bson:"error_log_count"` } func (s *TaskStat) GetId() (id primitive.ObjectID) { return s.Id } func (s *TaskStat) SetId(id primitive.ObjectID) { s.Id = id } func (s *TaskStat) GetCreateTs() (ts time.Time) { return s.CreateTs } func (s *TaskStat) SetCreateTs(ts time.Time) { s.CreateTs = ts } func (s *TaskStat) GetStartTs() (ts time.Time) { return s.StartTs } func (s *TaskStat) SetStartTs(ts time.Time) { s.StartTs = ts } func (s *TaskStat) GetEndTs() (ts time.Time) { return s.EndTs } func (s *TaskStat) SetEndTs(ts time.Time) { s.EndTs = ts } func (s *TaskStat) GetWaitDuration() (d int64) { return s.WaitDuration } func (s *TaskStat) SetWaitDuration(d int64) { s.WaitDuration = d } func (s *TaskStat) GetRuntimeDuration() (d int64) { return s.RuntimeDuration } func (s *TaskStat) SetRuntimeDuration(d int64) { s.RuntimeDuration = d } func (s *TaskStat) GetTotalDuration() (d int64) { return s.WaitDuration + s.RuntimeDuration } func (s *TaskStat) SetTotalDuration(d int64) { s.TotalDuration = d } func (s *TaskStat) GetResultCount() (c int64) { return s.ResultCount } func (s *TaskStat) SetResultCount(c int64) { s.ResultCount = c } func (s *TaskStat) GetErrorLogCount() (c int64) { return s.ErrorLogCount } func (s *TaskStat) SetErrorLogCount(c int64) { s.ErrorLogCount = c } type TaskStatList []TaskStat func (l *TaskStatList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/token.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Token struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Name string `json:"name" bson:"name"` Token string `json:"token" bson:"token"` } func (t *Token) GetId() (id primitive.ObjectID) { return t.Id } func (t *Token) SetId(id primitive.ObjectID) { t.Id = id } type TokenList []Token func (l *TokenList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/user.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type User struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Username string `json:"username" bson:"username"` Password string `json:"password,omitempty" bson:"-"` Role string `json:"role" bson:"role"` Email string `json:"email" bson:"email"` //Setting UserSetting `json:"setting" bson:"setting"` } func (u *User) GetId() (id primitive.ObjectID) { return u.Id } func (u *User) SetId(id primitive.ObjectID) { u.Id = id } func (u *User) GetUsername() (name string) { return u.Username } func (u *User) GetPassword() (p string) { return u.Password } func (u *User) GetRole() (r string) { return u.Role } func (u *User) GetEmail() (email string) { return u.Email } //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"` //} type UserList []User func (l *UserList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/user_role.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type UserRole struct { Id primitive.ObjectID `json:"_id" bson:"_id"` RoleId primitive.ObjectID `json:"role_id" bson:"role_id"` UserId primitive.ObjectID `json:"user_id" bson:"user_id"` } func (ur *UserRole) GetId() (id primitive.ObjectID) { return ur.Id } func (ur *UserRole) SetId(id primitive.ObjectID) { ur.Id = id } type UserRoleList []UserRole func (l *UserRoleList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/models/utils_binder_legacy.go ================================================ package models //func AssignFields(d interface{}, fieldIds ...interfaces.ModelId) (res interface{}, err error) { // return assignFields(d, fieldIds...) //} // //func AssignListFields(list interface{}, fieldIds ...interfaces.ModelId) (res arraylist.List, err error) { // return assignListFields(list, fieldIds...) //} // //func AssignListFieldsAsPtr(list interface{}, fieldIds ...interfaces.ModelId) (res arraylist.List, err error) { // return assignListFieldsAsPtr(list, fieldIds...) //} // //func assignFields(d interface{}, fieldIds ...interfaces.ModelId) (res interface{}, err error) { // doc, ok := d.(interfaces.Model) // if !ok { // return nil, errors.ErrorModelInvalidType // } // if len(fieldIds) == 0 { // return doc, nil // } // for _, fid := range fieldIds { // switch fid { // case interfaces.ModelIdTag: // // convert interface // d, ok := doc.(interfaces.ModelWithTags) // if !ok { // return nil, errors.ErrorModelInvalidType // } // // // attempt to get artifact // a, err := doc.GetArtifact() // if err != nil { // return nil, err // } // // // skip if no artifact found // if a == nil { // return d, nil // } // // // assign tags // tags, err := a.GetTags() // if err != nil { // return nil, err // } // d.SetTags(tags) // // return d, nil // } // } // return doc, nil //} // //func _assignListFields(asPtr bool, list interface{}, fieldIds ...interfaces.ModelId) (res arraylist.List, err error) { // vList := reflect.ValueOf(list) // if vList.Kind() != reflect.Array && // vList.Kind() != reflect.Slice { // return res, errors.ErrorModelInvalidType // } // for i := 0; i < vList.Len(); i++ { // vItem := vList.Index(i) // var item interface{} // if vItem.CanAddr() { // item = vItem.Addr().Interface() // } else { // item = vItem.Interface() // } // doc, ok := item.(interfaces.Model) // if !ok { // return res, errors.ErrorModelInvalidType // } // ptr, err := assignFields(doc, fieldIds...) // if err != nil { // return res, err // } // v := reflect.ValueOf(ptr) // if !asPtr { // // non-pointer item // res.Add(v.Elem().Interface()) // } else { // // pointer item // res.Add(v.Interface()) // } // } // return res, nil //} // //func assignListFields(list interface{}, fieldIds ...interfaces.ModelId) (res arraylist.List, err error) { // return _assignListFields(false, list, fieldIds...) //} // //func assignListFieldsAsPtr(list interface{}, fieldIds ...interfaces.ModelId) (res arraylist.List, err error) { // return _assignListFields(true, list, fieldIds...) //} ================================================ FILE: core/models/models/utils_col.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils/binders" ) func GetModelColName(id interfaces.ModelId) (colName string) { return binders.NewColNameBinder(id).MustBindString() } ================================================ FILE: core/models/models/utils_model_map.go ================================================ package models type ModelMap struct { Artifact Artifact Tag Tag Node Node Project Project Spider Spider Task Task Job Job Schedule Schedule User User Setting Setting Token Token Variable Variable TaskQueueItem TaskQueueItem TaskStat TaskStat SpiderStat SpiderStat DataSource DataSource DataCollection DataCollection Result Result Password Password ExtraValue ExtraValue Git Git Role Role UserRole UserRole Permission Permission RolePermission RolePermission Environment Environment DependencySetting DependencySetting } type ModelListMap struct { Artifacts ArtifactList Tags TagList Nodes NodeList Projects ProjectList Spiders SpiderList Tasks TaskList Jobs JobList Schedules ScheduleList Users UserList Settings SettingList Tokens TokenList Variables VariableList TaskQueueItems TaskQueueItemList TaskStats TaskStatList SpiderStats SpiderStatList DataSources DataSourceList DataCollections DataCollectionList Results ResultList Passwords PasswordList ExtraValues ExtraValueList Gits GitList Roles RoleList UserRoles UserRoleList PermissionList PermissionList RolePermissionList RolePermissionList Environments EnvironmentList DependencySettings DependencySettingList } func NewModelMap() (m *ModelMap) { return &ModelMap{} } func NewModelListMap() (m *ModelListMap) { return &ModelListMap{ Artifacts: ArtifactList{}, Tags: TagList{}, Nodes: NodeList{}, Projects: ProjectList{}, Spiders: SpiderList{}, Tasks: TaskList{}, Jobs: JobList{}, Schedules: ScheduleList{}, Users: UserList{}, Settings: SettingList{}, Tokens: TokenList{}, Variables: VariableList{}, TaskQueueItems: TaskQueueItemList{}, TaskStats: TaskStatList{}, SpiderStats: SpiderStatList{}, DataSources: DataSourceList{}, DataCollections: DataCollectionList{}, Results: ResultList{}, Passwords: PasswordList{}, ExtraValues: ExtraValueList{}, Gits: GitList{}, Roles: RoleList{}, PermissionList: PermissionList{}, RolePermissionList: RolePermissionList{}, Environments: EnvironmentList{}, } } ================================================ FILE: core/models/models/utils_tag.go ================================================ package models import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/trace" ) func convertInterfacesToTags(tags []interfaces.Tag) (res []Tag) { if tags == nil { return nil } for _, t := range tags { tag, ok := t.(*Tag) if !ok { log.Warnf("%v: cannot convert tag", trace.TraceError(errors.ErrorModelInvalidType)) return nil } if tag == nil { log.Warnf("%v: cannot convert tag", trace.TraceError(errors.ErrorModelInvalidType)) return nil } res = append(res, *tag) } return res } func convertTagsToInterfaces(tags []Tag) (res []interfaces.Tag) { for _, t := range tags { res = append(res, &t) } return res } ================================================ FILE: core/models/models/v2/base_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" "time" ) type BaseModelV2[T any] struct { Id primitive.ObjectID `json:"_id" bson:"_id"` CreatedAt time.Time `json:"created_ts,omitempty" bson:"created_ts,omitempty"` CreatedBy primitive.ObjectID `json:"created_by,omitempty" bson:"created_by,omitempty"` UpdatedAt time.Time `json:"updated_ts,omitempty" bson:"updated_ts,omitempty"` UpdatedBy primitive.ObjectID `json:"updated_by,omitempty" bson:"updated_by,omitempty"` } func (m *BaseModelV2[T]) GetId() primitive.ObjectID { return m.Id } func (m *BaseModelV2[T]) SetId(id primitive.ObjectID) { m.Id = id } func (m *BaseModelV2[T]) GetCreatedAt() time.Time { return m.CreatedAt } func (m *BaseModelV2[T]) SetCreatedAt(t time.Time) { m.CreatedAt = t } func (m *BaseModelV2[T]) GetCreatedBy() primitive.ObjectID { return m.CreatedBy } func (m *BaseModelV2[T]) SetCreatedBy(id primitive.ObjectID) { m.CreatedBy = id } func (m *BaseModelV2[T]) GetUpdatedAt() time.Time { return m.UpdatedAt } func (m *BaseModelV2[T]) SetUpdatedAt(t time.Time) { m.UpdatedAt = t } func (m *BaseModelV2[T]) GetUpdatedBy() primitive.ObjectID { return m.UpdatedBy } func (m *BaseModelV2[T]) SetUpdatedBy(id primitive.ObjectID) { m.UpdatedBy = id } func (m *BaseModelV2[T]) SetCreated(id primitive.ObjectID) { m.SetCreatedAt(time.Now()) m.SetCreatedBy(id) } func (m *BaseModelV2[T]) SetUpdated(id primitive.ObjectID) { m.SetUpdatedAt(time.Now()) m.SetUpdatedBy(id) } ================================================ FILE: core/models/models/v2/data_collection_v2.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/entity" ) type DataCollectionV2 struct { any `collection:"data_collections"` BaseModelV2[DataCollectionV2] `bson:",inline"` Name string `json:"name" bson:"name"` Fields []entity.DataField `json:"fields" bson:"fields"` Dedup struct { Enabled bool `json:"enabled" bson:"enabled"` Keys []string `json:"keys" bson:"keys"` Type string `json:"type" bson:"type"` } `json:"dedup" bson:"dedup"` } ================================================ FILE: core/models/models/v2/database_metric_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type DatabaseMetricV2 struct { any `collection:"database_metrics"` BaseModelV2[DatabaseMetricV2] `bson:",inline"` DatabaseId primitive.ObjectID `json:"database_id" bson:"database_id"` CpuUsagePercent float32 `json:"cpu_usage_percent" bson:"cpu_usage_percent"` TotalMemory uint64 `json:"total_memory" bson:"total_memory"` AvailableMemory uint64 `json:"available_memory" bson:"available_memory"` UsedMemory uint64 `json:"used_memory" bson:"used_memory"` UsedMemoryPercent float32 `json:"used_memory_percent" bson:"used_memory_percent"` TotalDisk uint64 `json:"total_disk" bson:"total_disk"` AvailableDisk uint64 `json:"available_disk" bson:"available_disk"` UsedDisk uint64 `json:"used_disk" bson:"used_disk"` UsedDiskPercent float32 `json:"used_disk_percent" bson:"used_disk_percent"` Connections int `json:"connections" bson:"connections"` QueryPerSecond float64 `json:"query_per_second" bson:"query_per_second"` TotalQuery uint64 `json:"total_query,omitempty" bson:"total_query,omitempty"` CacheHitRatio float64 `json:"cache_hit_ratio" bson:"cache_hit_ratio"` ReplicationLag float64 `json:"replication_lag" bson:"replication_lag"` LockWaitTime float64 `json:"lock_wait_time" bson:"lock_wait_time"` } ================================================ FILE: core/models/models/v2/database_v2.go ================================================ package models import ( "time" ) type DatabaseV2 struct { any `collection:"databases"` BaseModelV2[DatabaseV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` DataSource string `json:"data_source" bson:"data_source"` Host string `json:"host" bson:"host"` Port int `json:"port" bson:"port"` URI string `json:"uri,omitempty" bson:"uri,omitempty"` Database string `json:"database,omitempty" bson:"database,omitempty"` Username string `json:"username,omitempty" bson:"username,omitempty"` Password string `json:"password,omitempty" bson:"-"` EncryptedPassword string `json:"-,omitempty" bson:"encrypted_password,omitempty"` Status string `json:"status" bson:"status"` Error string `json:"error" bson:"error"` Active bool `json:"active" bson:"active"` ActiveAt time.Time `json:"active_ts" bson:"active_ts"` IsDefault bool `json:"is_default" bson:"-"` MongoParams *struct { AuthSource string `json:"auth_source,omitempty" bson:"auth_source,omitempty"` AuthMechanism string `json:"auth_mechanism,omitempty" bson:"auth_mechanism,omitempty"` } `json:"mongo_params,omitempty" bson:"mongo_params,omitempty"` PostgresParams *struct { SSLMode string `json:"ssl_mode,omitempty" bson:"ssl_mode,omitempty"` } `json:"postgres_params,omitempty" bson:"postgres_params,omitempty"` SnowflakeParams *struct { Account string `json:"account,omitempty" bson:"account,omitempty"` Schema string `json:"schema,omitempty" bson:"schema,omitempty"` Warehouse string `json:"warehouse,omitempty" bson:"warehouse,omitempty"` Role string `json:"role,omitempty" bson:"role,omitempty"` } `json:"snowflake_params,omitempty" bson:"snowflake_params,omitempty"` CassandraParams *struct { Keyspace string `json:"keyspace,omitempty" bson:"keyspace,omitempty"` } `json:"cassandra_params,omitempty" bson:"cassandra_params,omitempty"` HiveParams *struct { Auth string `json:"auth,omitempty" bson:"auth,omitempty"` } `json:"hive_params,omitempty" bson:"hive_params,omitempty"` RedisParams *struct { DB int `json:"db,omitempty" bson:"db,omitempty"` } `json:"redis_params,omitempty" bson:"redis_params,omitempty"` } ================================================ FILE: core/models/models/v2/dependency_log_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type DependencyLogV2 struct { any `collection:"dependency_logs"` BaseModelV2[DependencyLogV2] `bson:",inline"` TaskId primitive.ObjectID `json:"task_id" bson:"task_id"` Content string `json:"content" bson:"content"` } ================================================ FILE: core/models/models/v2/dependency_setting_v2.go ================================================ package models import ( "time" ) type DependencySettingV2 struct { any `collection:"dependency_settings"` BaseModelV2[DependencySettingV2] `bson:",inline"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Enabled bool `json:"enabled" bson:"enabled"` Cmd string `json:"cmd" bson:"cmd"` Proxy string `json:"proxy" bson:"proxy"` LastUpdateTs time.Time `json:"last_update_ts" bson:"last_update_ts"` } ================================================ FILE: core/models/models/v2/dependency_task_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type DependencyTaskV2 struct { any `collection:"dependency_tasks"` BaseModelV2[DependencyTaskV2] `bson:",inline"` Status string `json:"status" bson:"status"` Error string `json:"error" bson:"error"` SettingId primitive.ObjectID `json:"setting_id" bson:"setting_id"` Type string `json:"type" bson:"type"` NodeId primitive.ObjectID `json:"node_id" bson:"node_id"` Action string `json:"action" bson:"action"` DepNames []string `json:"dep_names" bson:"dep_names"` } ================================================ FILE: core/models/models/v2/dependency_v2.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/entity" "go.mongodb.org/mongo-driver/bson/primitive" ) type DependencyV2 struct { any `collection:"dependencies"` BaseModelV2[DependencyV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` NodeId primitive.ObjectID `json:"node_id" bson:"node_id"` Type string `json:"type" bson:"type"` LatestVersion string `json:"latest_version" bson:"latest_version"` Version string `json:"version" bson:"version"` Result entity.DependencyResult `json:"result" bson:"-"` } ================================================ FILE: core/models/models/v2/environment_v2.go ================================================ package models type EnvironmentV2 struct { any `collection:"environments"` BaseModelV2[EnvironmentV2] `bson:",inline"` Key string `json:"key" bson:"key"` Value string `json:"value" bson:"value"` } ================================================ FILE: core/models/models/v2/git_v2.go ================================================ package models import ( "github.com/crawlab-team/crawlab/vcs" "time" ) type GitV2 struct { any `collection:"gits"` BaseModelV2[GitV2] `bson:",inline"` Url string `json:"url" bson:"url"` Name string `json:"name" bson:"name"` AuthType string `json:"auth_type" bson:"auth_type"` Username string `json:"username" bson:"username"` Password string `json:"password" bson:"password"` CurrentBranch string `json:"current_branch" bson:"current_branch"` Status string `json:"status" bson:"status"` Error string `json:"error" bson:"error"` Spiders []SpiderV2 `json:"spiders,omitempty" bson:"-"` Refs []vcs.GitRef `json:"refs" bson:"refs"` RefsUpdatedAt time.Time `json:"refs_updated_at" bson:"refs_updated_at"` CloneLogs []string `json:"clone_logs,omitempty" bson:"clone_logs"` // settings AutoPull bool `json:"auto_pull" bson:"auto_pull"` } ================================================ FILE: core/models/models/v2/metric_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type MetricV2 struct { any `collection:"metrics"` BaseModelV2[MetricV2] `bson:",inline"` Type string `json:"type" bson:"type"` NodeId primitive.ObjectID `json:"node_id" bson:"node_id"` CpuUsagePercent float32 `json:"cpu_usage_percent" bson:"cpu_usage_percent"` TotalMemory uint64 `json:"total_memory" bson:"total_memory"` AvailableMemory uint64 `json:"available_memory" bson:"available_memory"` UsedMemory uint64 `json:"used_memory" bson:"used_memory"` UsedMemoryPercent float32 `json:"used_memory_percent" bson:"used_memory_percent"` TotalDisk uint64 `json:"total_disk" bson:"total_disk"` AvailableDisk uint64 `json:"available_disk" bson:"available_disk"` UsedDisk uint64 `json:"used_disk" bson:"used_disk"` UsedDiskPercent float32 `json:"used_disk_percent" bson:"used_disk_percent"` DiskReadBytesRate float32 `json:"disk_read_bytes_rate" bson:"disk_read_bytes_rate"` DiskWriteBytesRate float32 `json:"disk_write_bytes_rate" bson:"disk_write_bytes_rate"` NetworkBytesSentRate float32 `json:"network_bytes_sent_rate" bson:"network_bytes_sent_rate"` NetworkBytesRecvRate float32 `json:"network_bytes_recv_rate" bson:"network_bytes_recv_rate"` } ================================================ FILE: core/models/models/v2/node_v2.go ================================================ package models import ( "time" ) type NodeV2 struct { any `collection:"nodes"` BaseModelV2[NodeV2] `bson:",inline"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Ip string `json:"ip" bson:"ip"` Mac string `json:"mac" bson:"mac"` Hostname string `json:"hostname" bson:"hostname"` Description string `json:"description" bson:"description"` IsMaster bool `json:"is_master" bson:"is_master"` Status string `json:"status" bson:"status"` Enabled bool `json:"enabled" bson:"enabled"` Active bool `json:"active" bson:"active"` ActiveAt time.Time `json:"active_at" bson:"active_ts"` AvailableRunners int `json:"available_runners" bson:"available_runners"` MaxRunners int `json:"max_runners" bson:"max_runners"` } ================================================ FILE: core/models/models/v2/notification_alert_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type NotificationAlertV2 struct { any `collection:"notification_alerts"` BaseModelV2[NotificationAlertV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Enabled bool `json:"enabled" bson:"enabled"` HasMetricTarget bool `json:"has_metric_target" bson:"has_metric_target"` MetricTargetId primitive.ObjectID `json:"metric_target_id,omitempty" bson:"metric_target_id,omitempty"` MetricName string `json:"metric_name" bson:"metric_name"` Operator string `json:"operator" bson:"operator"` LastingSeconds int `json:"lasting_seconds" bson:"lasting_seconds"` TargetValue float32 `json:"target_value" bson:"target_value"` Level string `json:"level" bson:"level"` TemplateKey string `json:"template_key,omitempty" bson:"template_key,omitempty"` } ================================================ FILE: core/models/models/v2/notification_channel_v2.go ================================================ package models type NotificationChannelV2 struct { any `collection:"notification_channels"` BaseModelV2[NotificationChannelV2] `bson:",inline"` Type string `json:"type" bson:"type"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Provider string `json:"provider" bson:"provider"` SMTPServer string `json:"smtp_server,omitempty" bson:"smtp_server,omitempty"` SMTPPort int `json:"smtp_port,omitempty" bson:"smtp_port,omitempty"` SMTPUsername string `json:"smtp_username,omitempty" bson:"smtp_username,omitempty"` SMTPPassword string `json:"smtp_password,omitempty" bson:"smtp_password,omitempty"` WebhookUrl string `json:"webhook_url,omitempty" bson:"webhook_url,omitempty"` TelegramBotToken string `json:"telegram_bot_token,omitempty" bson:"telegram_bot_token,omitempty"` TelegramChatId string `json:"telegram_chat_id,omitempty" bson:"telegram_chat_id,omitempty"` GoogleOAuth2Json string `json:"google_oauth2_json,omitempty" bson:"google_oauth2_json,omitempty"` } ================================================ FILE: core/models/models/v2/notification_request_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type NotificationRequestV2 struct { any `collection:"notification_requests"` BaseModelV2[NotificationRequestV2] `bson:",inline"` Status string `json:"status" bson:"status"` Error string `json:"error,omitempty" bson:"error,omitempty"` Title string `json:"title" bson:"title"` Content string `json:"content" bson:"content"` SenderEmail string `json:"sender_email,omitempty" bson:"sender_email,omitempty"` SenderName string `json:"sender_name,omitempty" bson:"sender_name,omitempty"` MailTo []string `json:"mail_to,omitempty" bson:"mail_to,omitempty"` MailCc []string `json:"mail_cc,omitempty" bson:"mail_cc,omitempty"` MailBcc []string `json:"mail_bcc,omitempty" bson:"mail_bcc,omitempty"` SettingId primitive.ObjectID `json:"setting_id" bson:"setting_id"` ChannelId primitive.ObjectID `json:"channel_id" bson:"channel_id"` Setting *NotificationSettingV2 `json:"setting,omitempty" bson:"-"` Channel *NotificationChannelV2 `json:"channel,omitempty" bson:"-"` } ================================================ FILE: core/models/models/v2/notification_setting_v2.go ================================================ package models import "go.mongodb.org/mongo-driver/bson/primitive" type NotificationSettingV2 struct { any `collection:"notification_settings"` BaseModelV2[NotificationSettingV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Enabled bool `json:"enabled" bson:"enabled"` Title string `json:"title,omitempty" bson:"title,omitempty"` Template string `json:"template" bson:"template"` TemplateMode string `json:"template_mode" bson:"template_mode"` TemplateMarkdown string `json:"template_markdown,omitempty" bson:"template_markdown,omitempty"` TemplateRichText string `json:"template_rich_text,omitempty" bson:"template_rich_text,omitempty"` TemplateRichTextJson string `json:"template_rich_text_json,omitempty" bson:"template_rich_text_json,omitempty"` TemplateTheme string `json:"template_theme,omitempty" bson:"template_theme,omitempty"` TaskTrigger string `json:"task_trigger" bson:"task_trigger"` Trigger string `json:"trigger" bson:"trigger"` SenderEmail string `json:"sender_email,omitempty" bson:"sender_email,omitempty"` UseCustomSenderEmail bool `json:"use_custom_sender_email,omitempty" bson:"use_custom_sender_email,omitempty"` SenderName string `json:"sender_name,omitempty" bson:"sender_name,omitempty"` MailTo []string `json:"mail_to,omitempty" bson:"mail_to,omitempty"` MailCc []string `json:"mail_cc,omitempty" bson:"mail_cc,omitempty"` MailBcc []string `json:"mail_bcc,omitempty" bson:"mail_bcc,omitempty"` ChannelIds []primitive.ObjectID `json:"channel_ids,omitempty" bson:"channel_ids,omitempty"` Channels []NotificationChannelV2 `json:"channels,omitempty" bson:"-"` AlertId primitive.ObjectID `json:"alert_id,omitempty" bson:"alert_id,omitempty"` } ================================================ FILE: core/models/models/v2/permission_v2.go ================================================ package models type PermissionV2 struct { any `collection:"permissions"` BaseModelV2[PermissionV2] `bson:",inline"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Type string `json:"type" bson:"type"` Target []string `json:"target" bson:"target"` Allow []string `json:"allow" bson:"allow"` Deny []string `json:"deny" bson:"deny"` } ================================================ FILE: core/models/models/v2/project_v2.go ================================================ package models type ProjectV2 struct { any `collection:"projects"` BaseModelV2[ProjectV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Spiders int `json:"spiders" bson:"-"` } ================================================ FILE: core/models/models/v2/role_permission_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type RolePermissionV2 struct { any `collection:"role_permissions"` BaseModelV2[RolePermissionV2] `bson:",inline"` RoleId primitive.ObjectID `json:"role_id" bson:"role_id"` PermissionId primitive.ObjectID `json:"permission_id" bson:"permission_id"` } ================================================ FILE: core/models/models/v2/role_v2.go ================================================ package models type RoleV2 struct { any `collection:"roles"` BaseModelV2[RoleV2] `bson:",inline"` Key string `json:"key" bson:"key"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` } ================================================ FILE: core/models/models/v2/schedule_v2.go ================================================ package models import ( "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson/primitive" ) type ScheduleV2 struct { any `collection:"schedules"` BaseModelV2[ScheduleV2] `bson:",inline"` Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` SpiderId primitive.ObjectID `json:"spider_id" bson:"spider_id"` Cron string `json:"cron" bson:"cron"` EntryId cron.EntryID `json:"entry_id" bson:"entry_id"` Cmd string `json:"cmd" bson:"cmd"` Param string `json:"param" bson:"param"` Mode string `json:"mode" bson:"mode"` NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` Priority int `json:"priority" bson:"priority"` Enabled bool `json:"enabled" bson:"enabled"` } ================================================ FILE: core/models/models/v2/setting_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson" ) type SettingV2 struct { any `collection:"settings"` BaseModelV2[SettingV2] `bson:",inline"` Key string `json:"key" bson:"key"` Value bson.M `json:"value" bson:"value"` } ================================================ FILE: core/models/models/v2/spider_stat_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type SpiderStatV2 struct { any `collection:"spider_stats"` BaseModelV2[SpiderStatV2] `bson:",inline"` LastTaskId primitive.ObjectID `json:"last_task_id" bson:"last_task_id,omitempty"` LastTask *TaskV2 `json:"last_task,omitempty" bson:"-"` Tasks int `json:"tasks" bson:"tasks"` Results int `json:"results" bson:"results"` WaitDuration int64 `json:"wait_duration" bson:"wait_duration,omitempty"` // in second RuntimeDuration int64 `json:"runtime_duration" bson:"runtime_duration,omitempty"` // in second TotalDuration int64 `json:"total_duration" bson:"total_duration,omitempty"` // in second AverageWaitDuration int64 `json:"average_wait_duration" bson:"-"` // in second AverageRuntimeDuration int64 `json:"average_runtime_duration" bson:"-"` // in second AverageTotalDuration int64 `json:"average_total_duration" bson:"-"` // in second } ================================================ FILE: core/models/models/v2/spider_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type SpiderV2 struct { any `collection:"spiders"` BaseModelV2[SpiderV2] `bson:",inline"` Name string `json:"name" bson:"name"` // spider name ColId primitive.ObjectID `json:"col_id" bson:"col_id"` // data collection id (deprecated) # TODO: remove this field in the future ColName string `json:"col_name,omitempty" bson:"col_name"` // data collection name DataSourceId primitive.ObjectID `json:"data_source_id" bson:"data_source_id"` // data source id DataSource *DatabaseV2 `json:"data_source,omitempty" bson:"-"` // data source Description string `json:"description" bson:"description"` // description ProjectId primitive.ObjectID `json:"project_id" bson:"project_id"` // Project.Id Mode string `json:"mode" bson:"mode"` // default Task.Mode NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` // default Task.NodeIds GitId primitive.ObjectID `json:"git_id" bson:"git_id"` // related Git.Id GitRootPath string `json:"git_root_path" bson:"git_root_path"` Git *GitV2 `json:"git,omitempty" bson:"-"` // stats Stat *SpiderStatV2 `json:"stat,omitempty" bson:"-"` // execution Cmd string `json:"cmd" bson:"cmd"` // execute command Param string `json:"param" bson:"param"` // default task param Priority int `json:"priority" bson:"priority"` AutoInstall bool `json:"auto_install" bson:"auto_install"` } ================================================ FILE: core/models/models/v2/task_queue_item_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskQueueItemV2 struct { any `collection:"task_queue"` BaseModelV2[TaskQueueItemV2] `bson:",inline"` Priority int `json:"p" bson:"p"` NodeId primitive.ObjectID `json:"nid,omitempty" bson:"nid,omitempty"` } ================================================ FILE: core/models/models/v2/task_stat_v2.go ================================================ package models import ( "time" ) type TaskStatV2 struct { any `collection:"task_stats"` BaseModelV2[TaskStatV2] `bson:",inline"` StartTs time.Time `json:"start_ts" bson:"start_ts,omitempty"` EndTs time.Time `json:"end_ts" bson:"end_ts,omitempty"` WaitDuration int64 `json:"wait_duration" bson:"wait_duration,omitempty"` // in millisecond RuntimeDuration int64 `json:"runtime_duration" bson:"runtime_duration,omitempty"` // in millisecond TotalDuration int64 `json:"total_duration" bson:"total_duration,omitempty"` // in millisecond ResultCount int64 `json:"result_count" bson:"result_count"` } ================================================ FILE: core/models/models/v2/task_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type TaskV2 struct { any `collection:"tasks"` BaseModelV2[TaskV2] `bson:",inline"` SpiderId primitive.ObjectID `json:"spider_id" bson:"spider_id"` Status string `json:"status" bson:"status"` NodeId primitive.ObjectID `json:"node_id" bson:"node_id"` Cmd string `json:"cmd" bson:"cmd"` Param string `json:"param" bson:"param"` Error string `json:"error" bson:"error"` Pid int `json:"pid" bson:"pid"` ScheduleId primitive.ObjectID `json:"schedule_id" bson:"schedule_id"` Type string `json:"type" bson:"type"` Mode string `json:"mode" bson:"mode"` NodeIds []primitive.ObjectID `json:"node_ids" bson:"node_ids"` ParentId primitive.ObjectID `json:"parent_id" bson:"parent_id"` Priority int `json:"priority" bson:"priority"` Stat *TaskStatV2 `json:"stat,omitempty" bson:"-"` HasSub bool `json:"has_sub" json:"has_sub"` SubTasks []TaskV2 `json:"sub_tasks,omitempty" bson:"-"` Spider *SpiderV2 `json:"spider,omitempty" bson:"-"` UserId primitive.ObjectID `json:"-" bson:"-"` } ================================================ FILE: core/models/models/v2/test_v2.go ================================================ package models type TestModelV2 struct { any `collection:"testmodels"` BaseModelV2[TestModelV2] `bson:",inline"` Name string `json:"name" bson:"name"` } ================================================ FILE: core/models/models/v2/token_v2.go ================================================ package models type TokenV2 struct { any `collection:"tokens"` BaseModelV2[TokenV2] `bson:",inline"` Name string `json:"name" bson:"name"` Token string `json:"token" bson:"token"` } ================================================ FILE: core/models/models/v2/user_role_v2.go ================================================ package models import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type UserRoleV2 struct { any `collection:"user_roles"` BaseModelV2[UserRoleV2] `bson:",inline"` RoleId primitive.ObjectID `json:"role_id" bson:"role_id"` UserId primitive.ObjectID `json:"user_id" bson:"user_id"` } ================================================ FILE: core/models/models/v2/user_v2.go ================================================ package models type UserV2 struct { any `collection:"users"` BaseModelV2[UserV2] `bson:",inline"` Username string `json:"username" bson:"username"` Password string `json:"-,omitempty" bson:"password"` Role string `json:"role" bson:"role"` Email string `json:"email" bson:"email"` } ================================================ FILE: core/models/models/v2/variable_v2.go ================================================ package models type VariableV2 struct { any `collection:"variables"` BaseModelV2[VariableV2] `bson:",inline"` Key string `json:"key" bson:"key"` Value string `json:"value" bson:"value"` Remark string `json:"remark" bson:"remark"` } ================================================ FILE: core/models/models/variable.go ================================================ package models import ( "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson/primitive" ) type Variable struct { Id primitive.ObjectID `json:"_id" bson:"_id"` Key string `json:"key" bson:"key"` Value string `json:"value" bson:"value"` Remark string `json:"remark" bson:"remark"` } func (v *Variable) GetId() (id primitive.ObjectID) { return v.Id } func (v *Variable) SetId(id primitive.ObjectID) { v.Id = id } type VariableList []Variable func (l *VariableList) GetModels() (res []interfaces.Model) { for i := range *l { d := (*l)[i] res = append(res, &d) } return res } ================================================ FILE: core/models/service/artifact_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeArtifact(d interface{}, err error) (res *models2.Artifact, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Artifact) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetArtifactById(id primitive.ObjectID) (res *models2.Artifact, err error) { d, err := svc.GetBaseService(interfaces.ModelIdArtifact).GetById(id) return convertTypeArtifact(d, err) } func (svc *Service) GetArtifact(query bson.M, opts *mongo.FindOptions) (res *models2.Artifact, err error) { d, err := svc.GetBaseService(interfaces.ModelIdArtifact).Get(query, opts) return convertTypeArtifact(d, err) } func (svc *Service) GetArtifactList(query bson.M, opts *mongo.FindOptions) (res []models2.Artifact, err error) { l, err := svc.GetBaseService(interfaces.ModelIdArtifact).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Artifact) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/base_service.go ================================================ package service import ( "encoding/json" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "reflect" "strings" "sync" "time" ) type BaseService struct { id interfaces.ModelId col *mongo.Col } func (svc *BaseService) GetModelId() (id interfaces.ModelId) { return svc.id } func (svc *BaseService) SetModelId(id interfaces.ModelId) { svc.id = id } func (svc *BaseService) GetCol() (col *mongo.Col) { return svc.col } func (svc *BaseService) SetCol(col *mongo.Col) { svc.col = col } func (svc *BaseService) GetById(id primitive.ObjectID) (res interfaces.Model, err error) { // find result fr := svc.findId(id) // bind return NewBasicBinder(svc.id, fr).Bind() } func (svc *BaseService) Get(query bson.M, opts *mongo.FindOptions) (res interfaces.Model, err error) { // find result fr := svc.find(query, opts) // bind return NewBasicBinder(svc.id, fr).Bind() } func (svc *BaseService) GetList(query bson.M, opts *mongo.FindOptions) (l interfaces.List, err error) { // find result tic := time.Now() log.Debugf("baseService.GetMany -> svc.find:start") log.Debugf("baseService.GetMany -> svc.id: %v", svc.id) log.Debugf("baseService.GetMany -> svc.col.GetName(): %v", svc.col.GetName()) log.Debugf("baseService.GetMany -> query: %v", query) log.Debugf("baseService.GetMany -> opts: %v", opts) fr := svc.find(query, opts) log.Debugf("baseService.GetMany -> svc.find:end. elapsed: %d ms", time.Now().Sub(tic).Milliseconds()) // bind return NewListBinder(svc.id, fr).Bind() } func (svc *BaseService) DeleteById(id primitive.ObjectID, args ...interface{}) (err error) { return svc.deleteId(id, args...) } func (svc *BaseService) Delete(query bson.M, args ...interface{}) (err error) { return svc.delete(query) } func (svc *BaseService) DeleteList(query bson.M, args ...interface{}) (err error) { return svc.deleteList(query) } func (svc *BaseService) ForceDeleteList(query bson.M, args ...interface{}) (err error) { return svc.forceDeleteList(query) } func (svc *BaseService) UpdateById(id primitive.ObjectID, update bson.M, args ...interface{}) (err error) { return svc.updateId(id, update) } func (svc *BaseService) Update(query bson.M, update bson.M, fields []string, args ...interface{}) (err error) { return svc.update(query, update, fields) } func (svc *BaseService) UpdateDoc(query bson.M, doc interfaces.Model, fields []string, args ...interface{}) (err error) { return svc.update(query, doc, fields) } func (svc *BaseService) Insert(u interfaces.User, docs ...interface{}) (err error) { log.Debugf("baseService.Insert -> svc.col.GetName(): %v", svc.col.GetName()) log.Debugf("baseService.Insert -> docs: %v", docs) return svc.insert(u, docs...) } func (svc *BaseService) Count(query bson.M) (total int, err error) { return svc.count(query) } func (svc *BaseService) findId(id primitive.ObjectID) (fr *mongo.FindResult) { if svc.col == nil { return mongo.NewFindResultWithError(constants.ErrMissingCol) } return svc.col.FindId(id) } func (svc *BaseService) find(query bson.M, opts *mongo.FindOptions) (fr *mongo.FindResult) { if svc.col == nil { return mongo.NewFindResultWithError(constants.ErrMissingCol) } return svc.col.Find(query, opts) } func (svc *BaseService) deleteId(id primitive.ObjectID, args ...interface{}) (err error) { if svc.col == nil { return trace.TraceError(constants.ErrMissingCol) } fr := svc.findId(id) doc, err := NewBasicBinder(svc.id, fr).Bind() if err != nil { return err } return delegate.NewModelDelegate(doc, svc._getUserFromArgs(args...)).Delete() } func (svc *BaseService) delete(query bson.M, args ...interface{}) (err error) { if svc.col == nil { return trace.TraceError(constants.ErrMissingCol) } var doc models2.BaseModel if err := svc.find(query, nil).One(&doc); err != nil { return err } return svc.deleteId(doc.Id, svc._getUserFromArgs(args...)) } func (svc *BaseService) deleteList(query bson.M, args ...interface{}) (err error) { if svc.col == nil { return trace.TraceError(constants.ErrMissingCol) } fr := svc.find(query, nil) list, err := NewListBinder(svc.id, fr).Bind() if err != nil { return err } for _, doc := range list.GetModels() { if err := delegate.NewModelDelegate(doc, svc._getUserFromArgs(args...)).Delete(); err != nil { return err } } return nil } func (svc *BaseService) forceDeleteList(query bson.M, args ...interface{}) (err error) { return svc.col.Delete(query) } func (svc *BaseService) count(query bson.M) (total int, err error) { if svc.col == nil { return total, trace.TraceError(constants.ErrMissingCol) } return svc.col.Count(query) } func (svc *BaseService) update(query bson.M, update interface{}, fields []string, args ...interface{}) (err error) { update, err = svc._getUpdateBsonM(update, fields) if err != nil { return err } return svc._update(query, update, svc._getUserFromArgs(args...)) } func (svc *BaseService) updateId(id primitive.ObjectID, update interface{}, args ...interface{}) (err error) { update, err = svc._getUpdateBsonM(update, nil) if err != nil { return err } return svc._updateById(id, update, svc._getUserFromArgs(args...)) } func (svc *BaseService) insert(u interfaces.User, docs ...interface{}) (err error) { // validate col if svc.col == nil { return trace.TraceError(constants.ErrMissingCol) } // iterate docs for i, doc := range docs { switch doc.(type) { case map[string]interface{}: // doc type: map[string]interface{}, need to handle _id d := doc.(map[string]interface{}) vId, ok := d["_id"] if !ok { // _id not exists d["_id"] = primitive.NewObjectID() } else { // _id exists switch vId.(type) { case string: // _id type: string sId, ok := vId.(string) if ok { d["_id"], err = primitive.ObjectIDFromHex(sId) if err != nil { return trace.TraceError(err) } } case primitive.ObjectID: // _id type: primitive.ObjectID // do nothing default: return trace.TraceError(errors.ErrorModelInvalidType) } } } docs[i] = doc } // perform insert ids, err := svc.col.InsertMany(docs) if err != nil { return err } // upsert artifacts query := bson.M{ "_id": bson.M{ "$in": ids, }, } fr := svc.col.Find(query, nil) list, err := NewListBinder(svc.id, fr).Bind() for _, doc := range list.GetModels() { // upsert artifact when performing model delegate save if err := delegate.NewModelDelegate(doc, u).Save(); err != nil { return err } } return nil } func (svc *BaseService) _update(query bson.M, update interface{}, args ...interface{}) (err error) { // ids of query var ids []primitive.ObjectID list, err := NewListBinder(svc.id, svc.find(query, nil)).Bind() if err != nil { return err } for _, doc := range list.GetModels() { ids = append(ids, doc.GetId()) } // update model objects if err := svc.col.Update(query, update); err != nil { return err } // update artifacts u := svc._getUserFromArgs(args...) return mongo.GetMongoCol(interfaces.ModelColNameArtifact).Update(query, svc._getUpdateArtifactUpdate(u)) } func (svc *BaseService) _updateById(id primitive.ObjectID, update interface{}, args ...interface{}) (err error) { // update model object if err := svc.col.UpdateId(id, update); err != nil { return err } // update artifact u := svc._getUserFromArgs(args...) return mongo.GetMongoCol(interfaces.ModelColNameArtifact).UpdateId(id, svc._getUpdateArtifactUpdate(u)) } func (svc *BaseService) _getUpdateBsonM(update interface{}, fields []string) (res bson.M, err error) { switch update.(type) { case interfaces.Model: // convert to bson.M var updateBsonM bson.M bytes, err := json.Marshal(&update) if err != nil { return nil, err } if err := json.Unmarshal(bytes, &updateBsonM); err != nil { return nil, err } return svc._getUpdateBsonM(updateBsonM, fields) case bson.M: // convert to bson.M updateBsonM := update.(bson.M) // filter fields if not nil if fields != nil { // fields map fieldsMap := map[string]bool{} for _, f := range fields { fieldsMap[f] = true } // remove unselected fields for k := range updateBsonM { if _, ok := fieldsMap[k]; !ok { delete(updateBsonM, k) } } } // normalize update bson.M if !svc._containsDollar(updateBsonM) { if _, ok := updateBsonM["$set"]; !ok { updateBsonM = bson.M{ "$set": updateBsonM, } } } return updateBsonM, nil } v := reflect.ValueOf(update) switch v.Kind() { case reflect.Struct: if v.CanAddr() { update = v.Addr().Interface() return svc._getUpdateBsonM(update, fields) } return nil, errors.ErrorModelInvalidType default: return nil, errors.ErrorModelInvalidType } } func (svc *BaseService) _getUpdateArtifactUpdate(u interfaces.User) (res bson.M) { var uid primitive.ObjectID if u != nil { uid = u.GetId() } return bson.M{ "$set": bson.M{ "_sys.update_ts": time.Now(), "_sys.update_uid": uid, }, } } func (svc *BaseService) _getUserFromArgs(args ...interface{}) (u interfaces.User) { return utils.GetUserFromArgs(args...) } func (svc *BaseService) _containsDollar(updateBsonM bson.M) (ok bool) { for k := range updateBsonM { if strings.HasPrefix(k, "$") { return true } } return false } func NewBaseService(id interfaces.ModelId, opts ...BaseServiceOption) (svc2 interfaces.ModelBaseService) { // service svc := &BaseService{ id: id, } // apply options for _, opt := range opts { opt(svc) } // get collection name if not set if svc.GetCol() == nil { colName := models2.GetModelColName(id) svc.SetCol(mongo.GetMongoCol(colName)) } return svc } var store = sync.Map{} func GetBaseService(id interfaces.ModelId) (svc interfaces.ModelBaseService) { res, ok := store.Load(id) if ok { svc, ok = res.(interfaces.ModelBaseService) if ok { return svc } } svc = NewBaseService(id) store.Store(id, svc) return svc } func GetBaseServiceByColName(id interfaces.ModelId, colName string) (svc interfaces.ModelBaseService) { res, ok := store.Load(colName) if ok { svc, ok = res.(interfaces.ModelBaseService) if ok { return svc } } col := mongo.GetMongoCol(colName) svc = NewBaseService(id, WithBaseServiceCol(col)) store.Store(colName, svc) return svc } ================================================ FILE: core/models/service/base_service_v2.go ================================================ package service import ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo/options" "reflect" "sync" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) var ( instanceMap = make(map[string]any) onceMap = make(map[string]*sync.Once) onceColNameMap = make(map[string]*sync.Once) mu sync.Mutex ) type ModelServiceV2[T any] struct { col *mongo.Col } func (svc *ModelServiceV2[T]) GetById(id primitive.ObjectID) (model *T, err error) { var result T err = svc.col.FindId(id).One(&result) if err != nil { return nil, err } return &result, nil } func (svc *ModelServiceV2[T]) GetByIdContext(ctx context.Context, id primitive.ObjectID) (model *T, err error) { var result T err = svc.col.GetCollection().FindOne(ctx, bson.M{"_id": id}).Decode(&result) if err != nil { return nil, err } return &result, nil } func (svc *ModelServiceV2[T]) GetOne(query bson.M, options *mongo.FindOptions) (model *T, err error) { var result T err = svc.col.Find(query, options).One(&result) if err != nil { return nil, err } return &result, nil } func (svc *ModelServiceV2[T]) GetOneContext(ctx context.Context, query bson.M, opts *mongo.FindOptions) (model *T, err error) { var result T _opts := &options.FindOneOptions{} if opts != nil { if opts.Skip != 0 { skipInt64 := int64(opts.Skip) _opts.Skip = &skipInt64 } if opts.Sort != nil { _opts.Sort = opts.Sort } } err = svc.col.GetCollection().FindOne(ctx, query, _opts).Decode(&result) if err != nil { return nil, err } return &result, nil } func (svc *ModelServiceV2[T]) GetMany(query bson.M, options *mongo.FindOptions) (models []T, err error) { var result []T err = svc.col.Find(query, options).All(&result) if err != nil { return nil, err } return result, nil } func (svc *ModelServiceV2[T]) GetManyContext(ctx context.Context, query bson.M, opts *mongo.FindOptions) (models []T, err error) { var result []T _opts := &options.FindOptions{} if opts != nil { if opts.Skip != 0 { skipInt64 := int64(opts.Skip) _opts.Skip = &skipInt64 } if opts.Limit != 0 { limitInt64 := int64(opts.Limit) _opts.Limit = &limitInt64 } if opts.Sort != nil { _opts.Sort = opts.Sort } } cur, err := svc.col.GetCollection().Find(ctx, query, _opts) if err != nil { return nil, err } defer cur.Close(ctx) for cur.Next(ctx) { var model T if err := cur.Decode(&model); err != nil { return nil, err } result = append(result, model) } return result, nil } func (svc *ModelServiceV2[T]) DeleteById(id primitive.ObjectID) (err error) { return svc.col.DeleteId(id) } func (svc *ModelServiceV2[T]) DeleteByIdContext(ctx context.Context, id primitive.ObjectID) (err error) { _, err = svc.col.GetCollection().DeleteOne(ctx, bson.M{"_id": id}) return err } func (svc *ModelServiceV2[T]) DeleteOne(query bson.M) (err error) { _, err = svc.col.GetCollection().DeleteOne(svc.col.GetContext(), query) return err } func (svc *ModelServiceV2[T]) DeleteOneContext(ctx context.Context, query bson.M) (err error) { _, err = svc.col.GetCollection().DeleteOne(ctx, query) return err } func (svc *ModelServiceV2[T]) DeleteMany(query bson.M) (err error) { _, err = svc.col.GetCollection().DeleteMany(svc.col.GetContext(), query, nil) return err } func (svc *ModelServiceV2[T]) DeleteManyContext(ctx context.Context, query bson.M) (err error) { _, err = svc.col.GetCollection().DeleteMany(ctx, query, nil) return err } func (svc *ModelServiceV2[T]) UpdateById(id primitive.ObjectID, update bson.M) (err error) { return svc.col.UpdateId(id, update) } func (svc *ModelServiceV2[T]) UpdateByIdContext(ctx context.Context, id primitive.ObjectID, update bson.M) (err error) { _, err = svc.col.GetCollection().UpdateOne(ctx, bson.M{"_id": id}, update) return err } func (svc *ModelServiceV2[T]) UpdateOne(query bson.M, update bson.M) (err error) { _, err = svc.col.GetCollection().UpdateOne(svc.col.GetContext(), query, update) return err } func (svc *ModelServiceV2[T]) UpdateOneContext(ctx context.Context, query bson.M, update bson.M) (err error) { _, err = svc.col.GetCollection().UpdateOne(ctx, query, update) return err } func (svc *ModelServiceV2[T]) UpdateMany(query bson.M, update bson.M) (err error) { _, err = svc.col.GetCollection().UpdateMany(svc.col.GetContext(), query, update) return err } func (svc *ModelServiceV2[T]) UpdateManyContext(ctx context.Context, query bson.M, update bson.M) (err error) { _, err = svc.col.GetCollection().UpdateMany(ctx, query, update) return err } func (svc *ModelServiceV2[T]) ReplaceById(id primitive.ObjectID, model T) (err error) { _, err = svc.col.GetCollection().ReplaceOne(svc.col.GetContext(), bson.M{"_id": id}, model) return err } func (svc *ModelServiceV2[T]) ReplaceByIdContext(ctx context.Context, id primitive.ObjectID, model T) (err error) { _, err = svc.col.GetCollection().ReplaceOne(ctx, bson.M{"_id": id}, model) return err } func (svc *ModelServiceV2[T]) ReplaceOne(query bson.M, model T) (err error) { _, err = svc.col.GetCollection().ReplaceOne(svc.col.GetContext(), query, model) return err } func (svc *ModelServiceV2[T]) ReplaceOneContext(ctx context.Context, query bson.M, model T) (err error) { _, err = svc.col.GetCollection().ReplaceOne(ctx, query, model) return err } func (svc *ModelServiceV2[T]) InsertOne(model T) (id primitive.ObjectID, err error) { m := any(&model).(interfaces.Model) if m.GetId().IsZero() { m.SetId(primitive.NewObjectID()) } res, err := svc.col.GetCollection().InsertOne(svc.col.GetContext(), m) if err != nil { return primitive.NilObjectID, err } return res.InsertedID.(primitive.ObjectID), nil } func (svc *ModelServiceV2[T]) InsertOneContext(ctx context.Context, model T) (id primitive.ObjectID, err error) { m := any(&model).(interfaces.Model) if m.GetId().IsZero() { m.SetId(primitive.NewObjectID()) } res, err := svc.col.GetCollection().InsertOne(ctx, m) if err != nil { return primitive.NilObjectID, err } return res.InsertedID.(primitive.ObjectID), nil } func (svc *ModelServiceV2[T]) InsertMany(models []T) (ids []primitive.ObjectID, err error) { var _models []any for _, model := range models { m := any(&model).(interfaces.Model) if m.GetId().IsZero() { m.SetId(primitive.NewObjectID()) } _models = append(_models, m) } res, err := svc.col.GetCollection().InsertMany(svc.col.GetContext(), _models) if err != nil { return nil, err } for _, v := range res.InsertedIDs { ids = append(ids, v.(primitive.ObjectID)) } return ids, nil } func (svc *ModelServiceV2[T]) InsertManyContext(ctx context.Context, models []T) (ids []primitive.ObjectID, err error) { var _models []any for _, model := range models { m := any(&model).(interfaces.Model) if m.GetId().IsZero() { m.SetId(primitive.NewObjectID()) } _models = append(_models, m) } res, err := svc.col.GetCollection().InsertMany(ctx, _models) if err != nil { return nil, err } for _, v := range res.InsertedIDs { ids = append(ids, v.(primitive.ObjectID)) } return ids, nil } func (svc *ModelServiceV2[T]) Count(query bson.M) (total int, err error) { return svc.col.Count(query) } func (svc *ModelServiceV2[T]) GetCol() (col *mongo.Col) { return svc.col } func GetCollectionNameByInstance(v any) string { t := reflect.TypeOf(v) field := t.Field(0) return field.Tag.Get("collection") } func getCollectionName[T any]() string { var instance T t := reflect.TypeOf(instance) field := t.Field(0) return field.Tag.Get("collection") } // NewModelServiceV2 return singleton instance of ModelServiceV2 func NewModelServiceV2[T any]() *ModelServiceV2[T] { typeName := fmt.Sprintf("%T", *new(T)) mu.Lock() defer mu.Unlock() if _, exists := onceMap[typeName]; !exists { onceMap[typeName] = new(sync.Once) } var instance *ModelServiceV2[T] onceMap[typeName].Do(func() { collectionName := getCollectionName[T]() collection := mongo.GetMongoCol(collectionName) instance = &ModelServiceV2[T]{col: collection} instanceMap[typeName] = instance }) return instanceMap[typeName].(*ModelServiceV2[T]) } func NewModelServiceV2WithColName[T any](colName string) *ModelServiceV2[T] { mu.Lock() defer mu.Unlock() if _, exists := onceColNameMap[colName]; !exists { onceColNameMap[colName] = new(sync.Once) } var instance *ModelServiceV2[T] onceColNameMap[colName].Do(func() { collection := mongo.GetMongoCol(colName) instance = &ModelServiceV2[T]{col: collection} instanceMap[colName] = instance }) return instanceMap[colName].(*ModelServiceV2[T]) } ================================================ FILE: core/models/service/base_service_v2_test.go ================================================ package service_test import ( "context" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/db/mongo" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "testing" "time" ) type TestModel struct { Id primitive.ObjectID `bson:"_id,omitempty" collection:"testmodels"` models.BaseModelV2[TestModel] `bson:",inline"` Name string `bson:"name"` } func setupTestDB() { viper.Set("mongo.db", "testdb") } func teardownTestDB() { db := mongo.GetMongoDb("testdb") err := db.Drop(context.Background()) if err != nil { return } } func TestModelServiceV2_GetById(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Test Name"} id, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetById(id) require.Nil(t, err) assert.Equal(t, testModel.Name, result.Name) } func TestModelServiceV2_GetOne(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Test Name"} _, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetOne(bson.M{"name": "Test Name"}, nil) require.Nil(t, err) assert.Equal(t, testModel.Name, result.Name) } func TestModelServiceV2_GetMany(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Name1"}, {Name: "Name2"}, } _, err := svc.InsertMany(testModels) require.Nil(t, err) time.Sleep(100 * time.Millisecond) results, err := svc.GetMany(bson.M{}, nil) require.Nil(t, err) assert.Equal(t, 2, len(results)) } func TestModelServiceV2_InsertOne(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Test Name"} id, err := svc.InsertOne(testModel) require.Nil(t, err) assert.NotEqual(t, primitive.NilObjectID, id) } func TestModelServiceV2_InsertMany(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Name1"}, {Name: "Name2"}, } ids, err := svc.InsertMany(testModels) require.Nil(t, err) assert.Equal(t, 2, len(ids)) } func TestModelServiceV2_UpdateById(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Old Name"} id, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) update := bson.M{"$set": bson.M{"name": "New Name"}} err = svc.UpdateById(id, update) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetById(id) require.Nil(t, err) assert.Equal(t, "New Name", result.Name) } func TestModelServiceV2_UpdateOne(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Old Name"} _, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) update := bson.M{"$set": bson.M{"name": "New Name"}} err = svc.UpdateOne(bson.M{"name": "Old Name"}, update) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetOne(bson.M{"name": "New Name"}, nil) require.Nil(t, err) assert.Equal(t, "New Name", result.Name) } func TestModelServiceV2_UpdateMany(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Old Name1"}, {Name: "Old Name2"}, } _, err := svc.InsertMany(testModels) require.Nil(t, err) time.Sleep(100 * time.Millisecond) update := bson.M{"$set": bson.M{"name": "New Name"}} err = svc.UpdateMany(bson.M{"name": bson.M{"$regex": "^Old"}}, update) require.Nil(t, err) time.Sleep(100 * time.Millisecond) results, err := svc.GetMany(bson.M{"name": "New Name"}, nil) require.Nil(t, err) assert.Equal(t, 2, len(results)) } func TestModelServiceV2_DeleteById(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Test Name"} id, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) err = svc.DeleteById(id) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetById(id) assert.NotNil(t, err) assert.Nil(t, result) } func TestModelServiceV2_DeleteOne(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModel := TestModel{Name: "Test Name"} _, err := svc.InsertOne(testModel) require.Nil(t, err) time.Sleep(100 * time.Millisecond) err = svc.DeleteOne(bson.M{"name": "Test Name"}) require.Nil(t, err) time.Sleep(100 * time.Millisecond) result, err := svc.GetOne(bson.M{"name": "Test Name"}, nil) assert.NotNil(t, err) assert.Nil(t, result) } func TestModelServiceV2_DeleteMany(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Test Name1"}, {Name: "Test Name2"}, } _, err := svc.InsertMany(testModels) require.Nil(t, err) time.Sleep(100 * time.Millisecond) err = svc.DeleteMany(bson.M{"name": bson.M{"$regex": "^Test Name"}}) require.Nil(t, err) time.Sleep(100 * time.Millisecond) results, err := svc.GetMany(bson.M{"name": bson.M{"$regex": "^Test Name"}}, nil) require.Nil(t, err) assert.Equal(t, 0, len(results)) } func TestModelServiceV2_Count(t *testing.T) { setupTestDB() defer teardownTestDB() svc := service.NewModelServiceV2[TestModel]() testModels := []TestModel{ {Name: "Name1"}, {Name: "Name2"}, } _, err := svc.InsertMany(testModels) require.Nil(t, err) time.Sleep(100 * time.Millisecond) total, err := svc.Count(bson.M{}) require.Nil(t, err) assert.Equal(t, 2, total) } ================================================ FILE: core/models/service/binder_basic.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" ) func NewBasicBinder(id interfaces.ModelId, fr *mongo.FindResult) (b interfaces.ModelBinder) { return &BasicBinder{ id: id, fr: fr, m: models.NewModelMap(), } } type BasicBinder struct { id interfaces.ModelId fr *mongo.FindResult m *models.ModelMap } func (b *BasicBinder) Bind() (res interfaces.Model, err error) { m := b.m switch b.id { case interfaces.ModelIdArtifact: return b.Process(&m.Artifact) case interfaces.ModelIdTag: return b.Process(&m.Tag) case interfaces.ModelIdNode: return b.Process(&m.Node) case interfaces.ModelIdProject: return b.Process(&m.Project) case interfaces.ModelIdSpider: return b.Process(&m.Spider) case interfaces.ModelIdTask: return b.Process(&m.Task) case interfaces.ModelIdJob: return b.Process(&m.Job) case interfaces.ModelIdSchedule: return b.Process(&m.Schedule) case interfaces.ModelIdUser: return b.Process(&m.User) case interfaces.ModelIdSetting: return b.Process(&m.Setting) case interfaces.ModelIdToken: return b.Process(&m.Token) case interfaces.ModelIdVariable: return b.Process(&m.Variable) case interfaces.ModelIdTaskQueue: return b.Process(&m.TaskQueueItem) case interfaces.ModelIdTaskStat: return b.Process(&m.TaskStat) case interfaces.ModelIdSpiderStat: return b.Process(&m.SpiderStat) case interfaces.ModelIdDataSource: return b.Process(&m.DataSource) case interfaces.ModelIdDataCollection: return b.Process(&m.DataCollection) case interfaces.ModelIdResult: return b.Process(&m.Result) case interfaces.ModelIdPassword: return b.Process(&m.Password) case interfaces.ModelIdExtraValue: return b.Process(&m.ExtraValue) case interfaces.ModelIdGit: return b.Process(&m.Git) case interfaces.ModelIdRole: return b.Process(&m.Role) case interfaces.ModelIdUserRole: return b.Process(&m.UserRole) case interfaces.ModelIdPermission: return b.Process(&m.Permission) case interfaces.ModelIdRolePermission: return b.Process(&m.RolePermission) case interfaces.ModelIdEnvironment: return b.Process(&m.Environment) case interfaces.ModelIdDependencySetting: return b.Process(&m.DependencySetting) default: return nil, errors.ErrorModelInvalidModelId } } func (b *BasicBinder) Process(d interfaces.Model) (res interfaces.Model, err error) { if err := b.fr.One(d); err != nil { return nil, err } return d, nil } ================================================ FILE: core/models/service/binder_list.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" ) func NewListBinder(id interfaces.ModelId, fr *mongo.FindResult) (b interfaces.ModelListBinder) { return &ListBinder{ id: id, m: models.NewModelListMap(), fr: fr, b: NewBasicBinder(id, fr), } } type ListBinder struct { id interfaces.ModelId m *models.ModelListMap fr *mongo.FindResult b interfaces.ModelBinder } func (b *ListBinder) Bind() (l interfaces.List, err error) { m := b.m switch b.id { case interfaces.ModelIdArtifact: return b.Process(&m.Artifacts) case interfaces.ModelIdTag: return b.Process(&m.Tags) case interfaces.ModelIdNode: return b.Process(&m.Nodes) case interfaces.ModelIdProject: return b.Process(&m.Projects) case interfaces.ModelIdSpider: return b.Process(&m.Spiders) case interfaces.ModelIdTask: return b.Process(&m.Tasks) case interfaces.ModelIdSchedule: return b.Process(&m.Schedules) case interfaces.ModelIdUser: return b.Process(&m.Users) case interfaces.ModelIdSetting: return b.Process(&m.Settings) case interfaces.ModelIdToken: return b.Process(&m.Tokens) case interfaces.ModelIdVariable: return b.Process(&m.Variables) case interfaces.ModelIdTaskQueue: return b.Process(&m.TaskQueueItems) case interfaces.ModelIdTaskStat: return b.Process(&m.TaskStats) case interfaces.ModelIdSpiderStat: return b.Process(&m.SpiderStats) case interfaces.ModelIdDataSource: return b.Process(&m.DataSources) case interfaces.ModelIdDataCollection: return b.Process(&m.DataCollections) case interfaces.ModelIdResult: return b.Process(&m.Results) case interfaces.ModelIdPassword: return b.Process(&m.Passwords) case interfaces.ModelIdExtraValue: return b.Process(&m.ExtraValues) case interfaces.ModelIdGit: return b.Process(&m.Gits) case interfaces.ModelIdRole: return b.Process(&m.Roles) case interfaces.ModelIdUserRole: return b.Process(&m.UserRoles) case interfaces.ModelIdPermission: return b.Process(&m.PermissionList) case interfaces.ModelIdRolePermission: return b.Process(&m.RolePermissionList) case interfaces.ModelIdEnvironment: return b.Process(&m.Environments) case interfaces.ModelIdDependencySetting: return b.Process(&m.DependencySettings) default: return l, errors.ErrorModelInvalidModelId } } func (b *ListBinder) Process(d interface{}) (l interfaces.List, err error) { if err := b.fr.All(d); err != nil { return l, trace.TraceError(err) } return d.(interfaces.List), nil } ================================================ FILE: core/models/service/data_collection_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeDataCollection(d interface{}, err error) (res *models2.DataCollection, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.DataCollection) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetDataCollectionById(id primitive.ObjectID) (res *models2.DataCollection, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDataCollection).GetById(id) return convertTypeDataCollection(d, err) } func (svc *Service) GetDataCollection(query bson.M, opts *mongo.FindOptions) (res *models2.DataCollection, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDataCollection).Get(query, opts) return convertTypeDataCollection(d, err) } func (svc *Service) GetDataCollectionList(query bson.M, opts *mongo.FindOptions) (res []models2.DataCollection, err error) { l, err := svc.GetBaseService(interfaces.ModelIdDataCollection).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.DataCollection) res = append(res, *d) } return res, nil } func (svc *Service) GetDataCollectionByName(name string, opts *mongo.FindOptions) (res *models2.DataCollection, err error) { query := bson.M{"name": name} return svc.GetDataCollection(query, opts) } ================================================ FILE: core/models/service/data_source_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeDataSource(d interface{}, err error) (res *models2.DataSource, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.DataSource) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetDataSourceById(id primitive.ObjectID) (res *models2.DataSource, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDataSource).GetById(id) return convertTypeDataSource(d, err) } func (svc *Service) GetDataSource(query bson.M, opts *mongo.FindOptions) (res *models2.DataSource, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDataSource).Get(query, opts) return convertTypeDataSource(d, err) } func (svc *Service) GetDataSourceList(query bson.M, opts *mongo.FindOptions) (res []models2.DataSource, err error) { l, err := svc.GetBaseService(interfaces.ModelIdDataSource).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.DataSource) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/dependency_setting_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeDependencySetting(d interface{}, err error) (res *models2.DependencySetting, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.DependencySetting) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetDependencySettingById(id primitive.ObjectID) (res *models2.DependencySetting, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDependencySetting).GetById(id) return convertTypeDependencySetting(d, err) } func (svc *Service) GetDependencySetting(query bson.M, opts *mongo.FindOptions) (res *models2.DependencySetting, err error) { d, err := svc.GetBaseService(interfaces.ModelIdDependencySetting).Get(query, opts) return convertTypeDependencySetting(d, err) } func (svc *Service) GetDependencySettingList(query bson.M, opts *mongo.FindOptions) (res []models2.DependencySetting, err error) { l, err := svc.GetBaseService(interfaces.ModelIdDependencySetting).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.DependencySetting) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/environment_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeEnvironment(d interface{}, err error) (res *models2.Environment, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Environment) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetEnvironmentById(id primitive.ObjectID) (res *models2.Environment, err error) { d, err := svc.GetBaseService(interfaces.ModelIdEnvironment).GetById(id) return convertTypeEnvironment(d, err) } func (svc *Service) GetEnvironment(query bson.M, opts *mongo.FindOptions) (res *models2.Environment, err error) { d, err := svc.GetBaseService(interfaces.ModelIdEnvironment).Get(query, opts) return convertTypeEnvironment(d, err) } func (svc *Service) GetEnvironmentList(query bson.M, opts *mongo.FindOptions) (res []models2.Environment, err error) { l, err := svc.GetBaseService(interfaces.ModelIdEnvironment).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Environment) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/extra_value_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeExtraValue(d interface{}, err error) (res *models.ExtraValue, err2 error) { if err != nil { return nil, err } res, ok := d.(*models.ExtraValue) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetExtraValueById(id primitive.ObjectID) (res *models.ExtraValue, err error) { d, err := svc.GetBaseService(interfaces.ModelIdExtraValue).GetById(id) return convertTypeExtraValue(d, err) } func (svc *Service) GetExtraValue(query bson.M, opts *mongo.FindOptions) (res *models.ExtraValue, err error) { d, err := svc.GetBaseService(interfaces.ModelIdExtraValue).Get(query, opts) return convertTypeExtraValue(d, err) } func (svc *Service) GetExtraValueList(query bson.M, opts *mongo.FindOptions) (res []models.ExtraValue, err error) { l, err := svc.GetBaseService(interfaces.ModelIdExtraValue).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models.ExtraValue) res = append(res, *d) } return res, nil } func (svc *Service) GetExtraValueByObjectIdModel(oid primitive.ObjectID, m string, opts *mongo.FindOptions) (res *models.ExtraValue, err error) { d, err := svc.GetBaseService(interfaces.ModelIdExtraValue).Get(bson.M{"oid": oid, "m": m}, opts) return convertTypeExtraValue(d, err) } ================================================ FILE: core/models/service/git_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeGit(d interface{}, err error) (res *models2.Git, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Git) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetGitById(id primitive.ObjectID) (res *models2.Git, err error) { d, err := svc.GetBaseService(interfaces.ModelIdGit).GetById(id) return convertTypeGit(d, err) } func (svc *Service) GetGit(query bson.M, opts *mongo.FindOptions) (res *models2.Git, err error) { d, err := svc.GetBaseService(interfaces.ModelIdGit).Get(query, opts) return convertTypeGit(d, err) } func (svc *Service) GetGitList(query bson.M, opts *mongo.FindOptions) (res []models2.Git, err error) { l, err := svc.GetBaseService(interfaces.ModelIdGit).GetList(query, opts) if l == nil { return nil, nil } for _, doc := range l.GetModels() { d := doc.(*models2.Git) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/interface.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type ModelService interface { interfaces.ModelService DropAll() (err error) GetNodeById(id primitive.ObjectID) (res *models.Node, err error) GetNode(query bson.M, opts *mongo.FindOptions) (res *models.Node, err error) GetNodeList(query bson.M, opts *mongo.FindOptions) (res []models.Node, err error) GetNodeByKey(key string, opts *mongo.FindOptions) (res *models.Node, err error) GetProjectById(id primitive.ObjectID) (res *models.Project, err error) GetProject(query bson.M, opts *mongo.FindOptions) (res *models.Project, err error) GetProjectList(query bson.M, opts *mongo.FindOptions) (res []models.Project, err error) GetArtifactById(id primitive.ObjectID) (res *models.Artifact, err error) GetArtifact(query bson.M, opts *mongo.FindOptions) (res *models.Artifact, err error) GetArtifactList(query bson.M, opts *mongo.FindOptions) (res []models.Artifact, err error) GetTagById(id primitive.ObjectID) (res *models.Tag, err error) GetTag(query bson.M, opts *mongo.FindOptions) (res *models.Tag, err error) GetTagList(query bson.M, opts *mongo.FindOptions) (res []models.Tag, err error) GetTagIds(colName string, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) UpdateTagsById(colName string, id primitive.ObjectID, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) UpdateTags(colName string, query bson.M, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) GetJobById(id primitive.ObjectID) (res *models.Job, err error) GetJob(query bson.M, opts *mongo.FindOptions) (res *models.Job, err error) GetJobList(query bson.M, opts *mongo.FindOptions) (res []models.Job, err error) GetScheduleById(id primitive.ObjectID) (res *models.Schedule, err error) GetSchedule(query bson.M, opts *mongo.FindOptions) (res *models.Schedule, err error) GetScheduleList(query bson.M, opts *mongo.FindOptions) (res []models.Schedule, err error) GetUserById(id primitive.ObjectID) (res *models.User, err error) GetUser(query bson.M, opts *mongo.FindOptions) (res *models.User, err error) GetUserList(query bson.M, opts *mongo.FindOptions) (res []models.User, err error) GetUserByUsername(username string, opts *mongo.FindOptions) (res *models.User, err error) GetUserByUsernameWithPassword(username string, opts *mongo.FindOptions) (res *models.User, err error) GetSettingById(id primitive.ObjectID) (res *models.Setting, err error) GetSetting(query bson.M, opts *mongo.FindOptions) (res *models.Setting, err error) GetSettingList(query bson.M, opts *mongo.FindOptions) (res []models.Setting, err error) GetSettingByKey(key string, opts *mongo.FindOptions) (res *models.Setting, err error) GetSpiderById(id primitive.ObjectID) (res *models.Spider, err error) GetSpider(query bson.M, opts *mongo.FindOptions) (res *models.Spider, err error) GetSpiderList(query bson.M, opts *mongo.FindOptions) (res []models.Spider, err error) GetTaskById(id primitive.ObjectID) (res *models.Task, err error) GetTask(query bson.M, opts *mongo.FindOptions) (res *models.Task, err error) GetTaskList(query bson.M, opts *mongo.FindOptions) (res []models.Task, err error) GetTokenById(id primitive.ObjectID) (res *models.Token, err error) GetToken(query bson.M, opts *mongo.FindOptions) (res *models.Token, err error) GetTokenList(query bson.M, opts *mongo.FindOptions) (res []models.Token, err error) GetVariableById(id primitive.ObjectID) (res *models.Variable, err error) GetVariable(query bson.M, opts *mongo.FindOptions) (res *models.Variable, err error) GetVariableList(query bson.M, opts *mongo.FindOptions) (res []models.Variable, err error) GetVariableByKey(key string, opts *mongo.FindOptions) (res *models.Variable, err error) GetTaskQueueItemById(id primitive.ObjectID) (res *models.TaskQueueItem, err error) GetTaskQueueItem(query bson.M, opts *mongo.FindOptions) (res *models.TaskQueueItem, err error) GetTaskQueueItemList(query bson.M, opts *mongo.FindOptions) (res []models.TaskQueueItem, err error) GetTaskStatById(id primitive.ObjectID) (res *models.TaskStat, err error) GetTaskStat(query bson.M, opts *mongo.FindOptions) (res *models.TaskStat, err error) GetTaskStatList(query bson.M, opts *mongo.FindOptions) (res []models.TaskStat, err error) GetSpiderStatById(id primitive.ObjectID) (res *models.SpiderStat, err error) GetSpiderStat(query bson.M, opts *mongo.FindOptions) (res *models.SpiderStat, err error) GetSpiderStatList(query bson.M, opts *mongo.FindOptions) (res []models.SpiderStat, err error) GetDataSourceById(id primitive.ObjectID) (res *models.DataSource, err error) GetDataSource(query bson.M, opts *mongo.FindOptions) (res *models.DataSource, err error) GetDataSourceList(query bson.M, opts *mongo.FindOptions) (res []models.DataSource, err error) GetDataCollectionById(id primitive.ObjectID) (res *models.DataCollection, err error) GetDataCollection(query bson.M, opts *mongo.FindOptions) (res *models.DataCollection, err error) GetDataCollectionList(query bson.M, opts *mongo.FindOptions) (res []models.DataCollection, err error) GetDataCollectionByName(name string, opts *mongo.FindOptions) (res *models.DataCollection, err error) GetPasswordById(id primitive.ObjectID) (res *models.Password, err error) GetPassword(query bson.M, opts *mongo.FindOptions) (res *models.Password, err error) GetPasswordList(query bson.M, opts *mongo.FindOptions) (res []models.Password, err error) GetExtraValueById(id primitive.ObjectID) (res *models.ExtraValue, err error) GetExtraValue(query bson.M, opts *mongo.FindOptions) (res *models.ExtraValue, err error) GetExtraValueList(query bson.M, opts *mongo.FindOptions) (res []models.ExtraValue, err error) GetExtraValueByObjectIdModel(oid primitive.ObjectID, m string, opts *mongo.FindOptions) (res *models.ExtraValue, err error) GetGitById(id primitive.ObjectID) (res *models.Git, err error) GetGit(query bson.M, opts *mongo.FindOptions) (res *models.Git, err error) GetGitList(query bson.M, opts *mongo.FindOptions) (res []models.Git, err error) GetRoleById(id primitive.ObjectID) (res *models.Role, err error) GetRole(query bson.M, opts *mongo.FindOptions) (res *models.Role, err error) GetRoleList(query bson.M, opts *mongo.FindOptions) (res []models.Role, err error) GetRoleByName(name string, opts *mongo.FindOptions) (res *models.Role, err error) GetRoleByKey(key string, opts *mongo.FindOptions) (res *models.Role, err error) GetUserRoleById(id primitive.ObjectID) (res *models.UserRole, err error) GetUserRole(query bson.M, opts *mongo.FindOptions) (res *models.UserRole, err error) GetUserRoleList(query bson.M, opts *mongo.FindOptions) (res []models.UserRole, err error) GetUserRoleListByUserId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models.UserRole, err error) GetUserRoleListByRoleId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models.UserRole, err error) GetPermissionById(id primitive.ObjectID) (res *models.Permission, err error) GetPermission(query bson.M, opts *mongo.FindOptions) (res *models.Permission, err error) GetPermissionList(query bson.M, opts *mongo.FindOptions) (res []models.Permission, err error) GetPermissionByKey(key string, opts *mongo.FindOptions) (res *models.Permission, err error) GetRolePermission(query bson.M, opts *mongo.FindOptions) (res *models.RolePermission, err error) GetRolePermissionList(query bson.M, opts *mongo.FindOptions) (res []models.RolePermission, err error) GetRolePermissionListByRoleId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models.RolePermission, err error) GetRolePermissionListByPermissionId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models.RolePermission, err error) GetEnvironmentById(id primitive.ObjectID) (res *models.Environment, err error) GetEnvironment(query bson.M, opts *mongo.FindOptions) (res *models.Environment, err error) GetEnvironmentList(query bson.M, opts *mongo.FindOptions) (res []models.Environment, err error) } ================================================ FILE: core/models/service/job_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeJob(d interface{}, err error) (res *models2.Job, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Job) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetJobById(id primitive.ObjectID) (res *models2.Job, err error) { d, err := svc.GetBaseService(interfaces.ModelIdJob).GetById(id) return convertTypeJob(d, err) } func (svc *Service) GetJob(query bson.M, opts *mongo.FindOptions) (res *models2.Job, err error) { d, err := svc.GetBaseService(interfaces.ModelIdJob).Get(query, opts) return convertTypeJob(d, err) } func (svc *Service) GetJobList(query bson.M, opts *mongo.FindOptions) (res []models2.Job, err error) { l, err := svc.GetBaseService(interfaces.ModelIdJob).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Job) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/node_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeNode(d interface{}, err error) (res *models2.Node, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Node) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetNodeById(id primitive.ObjectID) (res *models2.Node, err error) { d, err := svc.GetBaseService(interfaces.ModelIdNode).GetById(id) return convertTypeNode(d, err) } func (svc *Service) GetNode(query bson.M, opts *mongo.FindOptions) (res *models2.Node, err error) { d, err := svc.GetBaseService(interfaces.ModelIdNode).Get(query, opts) return convertTypeNode(d, err) } func (svc *Service) GetNodeList(query bson.M, opts *mongo.FindOptions) (res []models2.Node, err error) { l, err := svc.GetBaseService(interfaces.ModelIdNode).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Node) res = append(res, *d) } return res, nil } func (svc *Service) GetNodeByKey(key string, opts *mongo.FindOptions) (res *models2.Node, err error) { query := bson.M{"key": key} return svc.GetNode(query, opts) } ================================================ FILE: core/models/service/options.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" ) type Option func(ModelService) type BaseServiceOption func(svc interfaces.ModelBaseService) func WithBaseServiceModelId(id interfaces.ModelId) BaseServiceOption { return func(svc interfaces.ModelBaseService) { svc.SetModelId(id) } } func WithBaseServiceCol(col *mongo.Col) BaseServiceOption { return func(svc interfaces.ModelBaseService) { _svc, ok := svc.(*BaseService) if ok { _svc.SetCol(col) } } } ================================================ FILE: core/models/service/password_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypePassword(d interface{}, err error) (res *models2.Password, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Password) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetPasswordById(id primitive.ObjectID) (res *models2.Password, err error) { d, err := svc.GetBaseService(interfaces.ModelIdPassword).GetById(id) return convertTypePassword(d, err) } func (svc *Service) GetPassword(query bson.M, opts *mongo.FindOptions) (res *models2.Password, err error) { d, err := svc.GetBaseService(interfaces.ModelIdPassword).Get(query, opts) return convertTypePassword(d, err) } func (svc *Service) GetPasswordList(query bson.M, opts *mongo.FindOptions) (res []models2.Password, err error) { l, err := svc.GetBaseService(interfaces.ModelIdPassword).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Password) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/permission_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypePermission(d interface{}, err error) (res *models2.Permission, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Permission) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetPermissionById(id primitive.ObjectID) (res *models2.Permission, err error) { d, err := svc.GetBaseService(interfaces.ModelIdPermission).GetById(id) return convertTypePermission(d, err) } func (svc *Service) GetPermission(query bson.M, opts *mongo.FindOptions) (res *models2.Permission, err error) { d, err := svc.GetBaseService(interfaces.ModelIdPermission).Get(query, opts) return convertTypePermission(d, err) } func (svc *Service) GetPermissionList(query bson.M, opts *mongo.FindOptions) (res []models2.Permission, err error) { l, err := svc.GetBaseService(interfaces.ModelIdPermission).GetList(query, opts) if err != nil { return nil, err } for _, doc := range l.GetModels() { d := doc.(*models2.Permission) res = append(res, *d) } return res, nil } func (svc *Service) GetPermissionByKey(key string, opts *mongo.FindOptions) (res *models2.Permission, err error) { query := bson.M{"key": key} return svc.GetPermission(query, opts) } ================================================ FILE: core/models/service/project_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeProject(d interface{}, err error) (res *models2.Project, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Project) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetProjectById(id primitive.ObjectID) (res *models2.Project, err error) { d, err := svc.GetBaseService(interfaces.ModelIdProject).GetById(id) return convertTypeProject(d, err) } func (svc *Service) GetProject(query bson.M, opts *mongo.FindOptions) (res *models2.Project, err error) { d, err := svc.GetBaseService(interfaces.ModelIdProject).Get(query, opts) return convertTypeProject(d, err) } func (svc *Service) GetProjectList(query bson.M, opts *mongo.FindOptions) (res []models2.Project, err error) { l, err := svc.GetBaseService(interfaces.ModelIdProject).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Project) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/role_permission_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeRolePermission(d interface{}, err error) (res *models2.RolePermission, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.RolePermission) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetRolePermissionById(id primitive.ObjectID) (res *models2.RolePermission, err error) { d, err := svc.GetBaseService(interfaces.ModelIdRolePermission).GetById(id) return convertTypeRolePermission(d, err) } func (svc *Service) GetRolePermission(query bson.M, opts *mongo.FindOptions) (res *models2.RolePermission, err error) { d, err := svc.GetBaseService(interfaces.ModelIdRolePermission).Get(query, opts) return convertTypeRolePermission(d, err) } func (svc *Service) GetRolePermissionList(query bson.M, opts *mongo.FindOptions) (res []models2.RolePermission, err error) { l, err := svc.GetBaseService(interfaces.ModelIdRolePermission).GetList(query, opts) if err != nil { return nil, err } for _, doc := range l.GetModels() { d := doc.(*models2.RolePermission) res = append(res, *d) } return res, nil } func (svc *Service) GetRolePermissionListByRoleId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models2.RolePermission, err error) { return svc.GetRolePermissionList(bson.M{"role_id": id}, opts) } func (svc *Service) GetRolePermissionListByPermissionId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models2.RolePermission, err error) { return svc.GetRolePermissionList(bson.M{"permission_id": id}, opts) } ================================================ FILE: core/models/service/role_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeRole(d interface{}, err error) (res *models2.Role, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Role) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetRoleById(id primitive.ObjectID) (res *models2.Role, err error) { d, err := svc.GetBaseService(interfaces.ModelIdRole).GetById(id) return convertTypeRole(d, err) } func (svc *Service) GetRole(query bson.M, opts *mongo.FindOptions) (res *models2.Role, err error) { d, err := svc.GetBaseService(interfaces.ModelIdRole).Get(query, opts) return convertTypeRole(d, err) } func (svc *Service) GetRoleList(query bson.M, opts *mongo.FindOptions) (res []models2.Role, err error) { l, err := svc.GetBaseService(interfaces.ModelIdRole).GetList(query, opts) if err != nil { return nil, err } for _, doc := range l.GetModels() { d := doc.(*models2.Role) res = append(res, *d) } return res, nil } func (svc *Service) GetRoleByName(name string, opts *mongo.FindOptions) (res *models2.Role, err error) { query := bson.M{"name": name} return svc.GetRole(query, opts) } func (svc *Service) GetRoleByKey(key string, opts *mongo.FindOptions) (res *models2.Role, err error) { query := bson.M{"key": key} return svc.GetRole(query, opts) } ================================================ FILE: core/models/service/schedule_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeSchedule(d interface{}, err error) (res *models2.Schedule, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Schedule) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetScheduleById(id primitive.ObjectID) (res *models2.Schedule, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSchedule).GetById(id) return convertTypeSchedule(d, err) } func (svc *Service) GetSchedule(query bson.M, opts *mongo.FindOptions) (res *models2.Schedule, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSchedule).Get(query, opts) return convertTypeSchedule(d, err) } func (svc *Service) GetScheduleList(query bson.M, opts *mongo.FindOptions) (res []models2.Schedule, err error) { l, err := svc.GetBaseService(interfaces.ModelIdSchedule).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Schedule) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/service.go ================================================ package service import ( "context" "github.com/crawlab-team/crawlab/core/color" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" mongo2 "go.mongodb.org/mongo-driver/mongo" ) type Service struct { env string colorSvc interfaces.ColorService } func (svc *Service) DropAll() (err error) { db := mongo.GetMongoDb("") colNames, err := db.ListCollectionNames(context.Background(), bson.M{}) if err != nil { if err == mongo2.ErrNoDocuments { return nil } return err } for _, colName := range colNames { col := db.Collection(colName) if err := col.Drop(context.Background()); err != nil { return err } } return nil } func (svc *Service) GetBaseService(id interfaces.ModelId) (svc2 interfaces.ModelBaseService) { return GetBaseService(id) } func NewService() (svc2 ModelService, err error) { // service svc := &Service{} svc.colorSvc, err = color.NewService() if err != nil { return nil, err } return svc, nil } var modelSvc ModelService func GetService() (svc ModelService, err error) { if modelSvc != nil { return modelSvc, nil } modelSvc, err = NewService() if err != nil { return nil, err } return modelSvc, nil } ================================================ FILE: core/models/service/setting_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeSetting(d interface{}, err error) (res *models2.Setting, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Setting) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetSettingById(id primitive.ObjectID) (res *models2.Setting, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSetting).GetById(id) return convertTypeSetting(d, err) } func (svc *Service) GetSetting(query bson.M, opts *mongo.FindOptions) (res *models2.Setting, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSetting).Get(query, opts) return convertTypeSetting(d, err) } func (svc *Service) GetSettingList(query bson.M, opts *mongo.FindOptions) (res []models2.Setting, err error) { l, err := svc.GetBaseService(interfaces.ModelIdSetting).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Setting) res = append(res, *d) } return res, nil } func (svc *Service) GetSettingByKey(key string, opts *mongo.FindOptions) (res *models2.Setting, err error) { query := bson.M{"key": key} return svc.GetSetting(query, opts) } ================================================ FILE: core/models/service/spider_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeSpider(d interface{}, err error) (res *models2.Spider, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Spider) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetSpiderById(id primitive.ObjectID) (res *models2.Spider, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSpider).GetById(id) return convertTypeSpider(d, err) } func (svc *Service) GetSpider(query bson.M, opts *mongo.FindOptions) (res *models2.Spider, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSpider).Get(query, opts) return convertTypeSpider(d, err) } func (svc *Service) GetSpiderList(query bson.M, opts *mongo.FindOptions) (res []models2.Spider, err error) { l, err := svc.GetBaseService(interfaces.ModelIdSpider).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Spider) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/spider_stat_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeSpiderStat(d interface{}, err error) (res *models2.SpiderStat, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.SpiderStat) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetSpiderStatById(id primitive.ObjectID) (res *models2.SpiderStat, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSpiderStat).GetById(id) return convertTypeSpiderStat(d, err) } func (svc *Service) GetSpiderStat(query bson.M, opts *mongo.FindOptions) (res *models2.SpiderStat, err error) { d, err := svc.GetBaseService(interfaces.ModelIdSpiderStat).Get(query, opts) return convertTypeSpiderStat(d, err) } func (svc *Service) GetSpiderStatList(query bson.M, opts *mongo.FindOptions) (res []models2.SpiderStat, err error) { l, err := svc.GetBaseService(interfaces.ModelIdSpiderStat).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.SpiderStat) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/tag_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" ) func convertTypeTag(d interface{}, err error) (res *models2.Tag, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Tag) if !ok { return nil, trace.TraceError(errors.ErrorModelInvalidType) } return res, nil } func (svc *Service) GetTagById(id primitive.ObjectID) (res *models2.Tag, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTag).GetById(id) return convertTypeTag(d, err) } func (svc *Service) GetTag(query bson.M, opts *mongo.FindOptions) (res *models2.Tag, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTag).Get(query, opts) return convertTypeTag(d, err) } func (svc *Service) GetTagList(query bson.M, opts *mongo.FindOptions) (res []models2.Tag, err error) { l, err := svc.GetBaseService(interfaces.ModelIdTag).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Tag) res = append(res, *d) } return res, nil } func (svc *Service) GetTagIds(colName string, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) { // iterate tag names for _, tag := range tags { // count of tags with the name tagDb, err := svc.GetTag(bson.M{"name": tag.GetName(), "col": colName}, nil) if err == nil { // tag exists tag = tagDb } else if err == mongo2.ErrNoDocuments { // add new tag if not exists colorHex := tag.GetColor() if colorHex == "" { color, _ := svc.colorSvc.GetRandom() colorHex = color.GetHex() } tag = &models2.Tag{ Id: primitive.NewObjectID(), Name: tag.GetName(), Color: colorHex, Col: colName, } if err := delegate.NewModelDelegate(tag).Add(); err != nil { return tagIds, trace.TraceError(err) } } // add to tag ids tagIds = append(tagIds, tag.GetId()) } return tagIds, nil } func (svc *Service) UpdateTagsById(colName string, id primitive.ObjectID, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) { // get tag ids to update tagIds, err = svc.GetTagIds(colName, tags) if err != nil { return tagIds, trace.TraceError(err) } // update in db a, err := svc.GetArtifactById(id) if err != nil { return tagIds, trace.TraceError(err) } a.TagIds = tagIds if err := mongo.GetMongoCol(interfaces.ModelColNameArtifact).ReplaceId(id, a); err != nil { return tagIds, err } return tagIds, nil } func (svc *Service) UpdateTags(colName string, query bson.M, tags []interfaces.Tag) (tagIds []primitive.ObjectID, err error) { // tag ids to update tagIds, err = svc.GetTagIds(colName, tags) if err != nil { return tagIds, trace.TraceError(err) } // update update := bson.M{ "_tid": tagIds, } // fields fields := []string{"_tid"} // update in db if err := svc.GetBaseService(interfaces.ModelIdTag).Update(query, update, fields); err != nil { return tagIds, trace.TraceError(err) } return tagIds, nil } ================================================ FILE: core/models/service/tag_service_legacy.go ================================================ package service // //import ( // "github.com/crawlab-team/crawlab/core/interfaces" // "github.com/crawlab-team/crawlab/db/mongo" // "go.mongodb.org/mongo-driver/bson" // "go.mongodb.org/mongo-driver/bson/primitive" // mongo2 "go.mongodb.org/mongo-driver/mongo" //) // //type TagServiceInterface interface { // getTagIds(colName string, tags []Tag) (tagIds []primitive.ObjectID, err error) // GetModelById(id primitive.ObjectID) (res Tag, err error) // GetModel(query bson.M, opts *mongo.FindOptions) (res Tag, err error) // GetModelList(query bson.M, opts *mongo.FindOptions) (res []Tag, err error) // UpdateTagsById(colName string, id primitive.ObjectID, tags []Tag) (tagIds []primitive.ObjectID, err error) // UpdateTags(colName string, query bson.M, tags []Tag) (tagIds []primitive.ObjectID, err error) //} // //type tagService struct { // *baseService //} // //func (svc *tagService) getTagIds(colName string, tags []Tag) (tagIds []primitive.ObjectID, err error) { // // iterate tag names // for _, tag := range tags { // // count of tags with the name // tagDb, err := MustGetRootService().GetTag(bson.M{"name": tag.Name, "col": colName}, nil) // if err == nil { // // tag exists // tag = tagDb // } else if err == mongo2.ErrNoDocuments { // // add new tag if not exists // colorHex := tag.Color // if colorHex == "" { // color, _ := ColorService.GetRandom() // colorHex = color.Hex // } // tag = Tag{ // Name: tag.Name, // Color: colorHex, // Col: colName, // } // if err := tag.Add(); err != nil { // return tagIds, err // } // } // // // add to tag ids // tagIds = append(tagIds, tag.Id) // } // // return tagIds, nil //} // //func (svc *tagService) GetModelById(id primitive.ObjectID) (res Tag, err error) { // err = svc.findId(id).One(&res) // return res, err //} // //func (svc *tagService) GetModel(query bson.M, opts *mongo.FindOptions) (res Tag, err error) { // err = svc.find(query, opts).One(&res) // return res, err //} // //func (svc *tagService) GetModelList(query bson.M, opts *mongo.FindOptions) (res []Tag, err error) { // err = svc.find(query, opts).All(&res) // return res, err //} // //func (svc *tagService) UpdateTagsById(colName string, id primitive.ObjectID, tags []Tag) (tagIds []primitive.ObjectID, err error) { // // get tag ids to update // tagIds, err = svc.getTagIds(colName, tags) // if err != nil { // return tagIds, err // } // // // update in db // a, err := MustGetRootService().GetArtifactById(id) // if err != nil { // return tagIds, err // } // a.TagIds = tagIds // if err := mongo.GetMongoCol(interfaces.ModelColNameArtifact).ReplaceId(id, a); err != nil { // return tagIds, err // } // return tagIds, nil //} // //func (svc *tagService) UpdateTags(colName string, query bson.M, tags []Tag) (tagIds []primitive.ObjectID, err error) { // // tag ids to update // tagIds, err = svc.getTagIds(colName, tags) // if err != nil { // return tagIds, err // } // // // update // update := bson.M{ // "_tid": tagIds, // } // // // fields // fields := []string{"_tid"} // // // update in db // if err := ArtifactService.Update(query, update, fields); err != nil { // return tagIds, err // } // // return tagIds, nil //} // //func NewTagService() (svc *tagService) { // return &tagService{svc.GetBaseService(interfaces.ModelIdTag)} //} // //var TagService *tagService ================================================ FILE: core/models/service/task_queue_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeTaskQueueItem(d interface{}, err error) (res *models2.TaskQueueItem, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.TaskQueueItem) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetTaskQueueItemById(id primitive.ObjectID) (res *models2.TaskQueueItem, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTaskQueue).GetById(id) return convertTypeTaskQueueItem(d, err) } func (svc *Service) GetTaskQueueItem(query bson.M, opts *mongo.FindOptions) (res *models2.TaskQueueItem, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTaskQueue).Get(query, opts) return convertTypeTaskQueueItem(d, err) } func (svc *Service) GetTaskQueueItemList(query bson.M, opts *mongo.FindOptions) (res []models2.TaskQueueItem, err error) { l, err := svc.GetBaseService(interfaces.ModelIdTaskQueue).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.TaskQueueItem) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/task_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeTask(d interface{}, err error) (res *models2.Task, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Task) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetTaskById(id primitive.ObjectID) (res *models2.Task, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTask).GetById(id) return convertTypeTask(d, err) } func (svc *Service) GetTask(query bson.M, opts *mongo.FindOptions) (res *models2.Task, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTask).Get(query, opts) return convertTypeTask(d, err) } func (svc *Service) GetTaskList(query bson.M, opts *mongo.FindOptions) (res []models2.Task, err error) { l, err := svc.GetBaseService(interfaces.ModelIdTask).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Task) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/task_stat_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeTaskStat(d interface{}, err error) (res *models2.TaskStat, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.TaskStat) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetTaskStatById(id primitive.ObjectID) (res *models2.TaskStat, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTaskStat).GetById(id) return convertTypeTaskStat(d, err) } func (svc *Service) GetTaskStat(query bson.M, opts *mongo.FindOptions) (res *models2.TaskStat, err error) { d, err := svc.GetBaseService(interfaces.ModelIdTaskStat).Get(query, opts) return convertTypeTaskStat(d, err) } func (svc *Service) GetTaskStatList(query bson.M, opts *mongo.FindOptions) (res []models2.TaskStat, err error) { l, err := svc.GetBaseService(interfaces.ModelIdTaskStat).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.TaskStat) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/token_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeToken(d interface{}, err error) (res *models2.Token, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Token) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetTokenById(id primitive.ObjectID) (res *models2.Token, err error) { d, err := svc.GetBaseService(interfaces.ModelIdToken).GetById(id) return convertTypeToken(d, err) } func (svc *Service) GetToken(query bson.M, opts *mongo.FindOptions) (res *models2.Token, err error) { d, err := svc.GetBaseService(interfaces.ModelIdToken).Get(query, opts) return convertTypeToken(d, err) } func (svc *Service) GetTokenList(query bson.M, opts *mongo.FindOptions) (res []models2.Token, err error) { l, err := svc.GetBaseService(interfaces.ModelIdToken).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Token) res = append(res, *d) } return res, nil } ================================================ FILE: core/models/service/user_role_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeUserRole(d interface{}, err error) (res *models2.UserRole, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.UserRole) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetUserRoleById(id primitive.ObjectID) (res *models2.UserRole, err error) { d, err := svc.GetBaseService(interfaces.ModelIdUserRole).GetById(id) return convertTypeUserRole(d, err) } func (svc *Service) GetUserRole(query bson.M, opts *mongo.FindOptions) (res *models2.UserRole, err error) { d, err := svc.GetBaseService(interfaces.ModelIdUserRole).Get(query, opts) return convertTypeUserRole(d, err) } func (svc *Service) GetUserRoleList(query bson.M, opts *mongo.FindOptions) (res []models2.UserRole, err error) { l, err := svc.GetBaseService(interfaces.ModelIdUserRole).GetList(query, opts) if err != nil { return nil, err } for _, doc := range l.GetModels() { d := doc.(*models2.UserRole) res = append(res, *d) } return res, nil } func (svc *Service) GetUserRoleListByUserId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models2.UserRole, err error) { return svc.GetUserRoleList(bson.M{"user_id": id}, opts) } func (svc *Service) GetUserRoleListByRoleId(id primitive.ObjectID, opts *mongo.FindOptions) (res []models2.UserRole, err error) { return svc.GetUserRoleList(bson.M{"role_id": id}, opts) } ================================================ FILE: core/models/service/user_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeUser(d interface{}, err error) (res *models2.User, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.User) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetUserById(id primitive.ObjectID) (res *models2.User, err error) { d, err := svc.GetBaseService(interfaces.ModelIdUser).GetById(id) return convertTypeUser(d, err) } func (svc *Service) GetUser(query bson.M, opts *mongo.FindOptions) (res *models2.User, err error) { d, err := svc.GetBaseService(interfaces.ModelIdUser).Get(query, opts) return convertTypeUser(d, err) } func (svc *Service) GetUserList(query bson.M, opts *mongo.FindOptions) (res []models2.User, err error) { l, err := svc.GetBaseService(interfaces.ModelIdUser).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.User) res = append(res, *d) } return res, nil } func (svc *Service) GetUserByUsername(username string, opts *mongo.FindOptions) (res *models2.User, err error) { query := bson.M{"username": username} return svc.GetUser(query, opts) } func (svc *Service) GetUserByUsernameWithPassword(username string, opts *mongo.FindOptions) (res *models2.User, err error) { u, err := svc.GetUserByUsername(username, opts) if err != nil { return nil, err } p, err := svc.GetPasswordById(u.Id) if err != nil { return nil, err } u.Password = p.Password return u, nil } ================================================ FILE: core/models/service/variable_service.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) func convertTypeVariable(d interface{}, err error) (res *models2.Variable, err2 error) { if err != nil { return nil, err } res, ok := d.(*models2.Variable) if !ok { return nil, errors.ErrorModelInvalidType } return res, nil } func (svc *Service) GetVariableById(id primitive.ObjectID) (res *models2.Variable, err error) { d, err := svc.GetBaseService(interfaces.ModelIdVariable).GetById(id) return convertTypeVariable(d, err) } func (svc *Service) GetVariable(query bson.M, opts *mongo.FindOptions) (res *models2.Variable, err error) { d, err := svc.GetBaseService(interfaces.ModelIdVariable).Get(query, opts) return convertTypeVariable(d, err) } func (svc *Service) GetVariableList(query bson.M, opts *mongo.FindOptions) (res []models2.Variable, err error) { l, err := svc.GetBaseService(interfaces.ModelIdVariable).GetList(query, opts) for _, doc := range l.GetModels() { d := doc.(*models2.Variable) res = append(res, *d) } return res, nil } func (svc *Service) GetVariableByKey(key string, opts *mongo.FindOptions) (res *models2.Variable, err error) { query := bson.M{"key": key} return svc.GetVariable(query, opts) } ================================================ FILE: core/node/config/config.go ================================================ package config import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/utils" "github.com/spf13/viper" ) type Config entity.NodeInfo type Options struct { Key string Name string IsMaster bool AuthKey string MaxRunners int } var DefaultMaxRunner = 8 var DefaultConfigOptions = &Options{ Key: utils.NewUUIDString(), IsMaster: utils.IsMaster(), AuthKey: constants.DefaultGrpcAuthKey, MaxRunners: 0, } func NewConfig(opts *Options) (cfg *Config) { if opts == nil { opts = DefaultConfigOptions } if opts.Key == "" { if viper.GetString("node.key") != "" { opts.Key = viper.GetString("node.key") } else { opts.Key = utils.NewUUIDString() } } if opts.Name == "" { if viper.GetString("node.name") != "" { opts.Name = viper.GetString("node.name") } else { opts.Name = opts.Key } } if opts.AuthKey == "" { if viper.GetString("grpc.authKey") != "" { opts.AuthKey = viper.GetString("grpc.authKey") } else { opts.AuthKey = constants.DefaultGrpcAuthKey } } if opts.MaxRunners == 0 { if viper.GetInt("task.handler.maxRunners") != 0 { opts.MaxRunners = viper.GetInt("task.handler.maxRunners") } else { opts.MaxRunners = DefaultMaxRunner } } return &Config{ Key: opts.Key, Name: opts.Name, IsMaster: opts.IsMaster, AuthKey: opts.AuthKey, MaxRunners: opts.MaxRunners, } } ================================================ FILE: core/node/config/config_service.go ================================================ package config import ( "encoding/json" "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "os" "path/filepath" "sync" ) type Service struct { cfg *Config path string } func (svc *Service) Init() (err error) { // check config directory path configDirPath := filepath.Dir(svc.path) if !utils.Exists(configDirPath) { if err := os.MkdirAll(configDirPath, os.FileMode(0766)); err != nil { return trace.TraceError(err) } } if !utils.Exists(svc.path) { // not exists, set to default config // and create a config file for persistence svc.cfg = NewConfig(nil) data, err := json.Marshal(svc.cfg) if err != nil { return trace.TraceError(err) } if err := os.WriteFile(svc.path, data, os.FileMode(0766)); err != nil { return trace.TraceError(err) } } else { // exists, read and set to config data, err := os.ReadFile(svc.path) if err != nil { return trace.TraceError(err) } if err := json.Unmarshal(data, svc.cfg); err != nil { return trace.TraceError(err) } } return nil } func (svc *Service) Reload() (err error) { return svc.Init() } func (svc *Service) GetBasicNodeInfo() (res interfaces.Entity) { res = &entity.NodeInfo{ Key: svc.GetNodeKey(), Name: svc.GetNodeName(), IsMaster: svc.IsMaster(), AuthKey: svc.GetAuthKey(), MaxRunners: svc.GetMaxRunners(), } return res } func (svc *Service) GetNodeKey() (res string) { return svc.cfg.Key } func (svc *Service) GetNodeName() (res string) { return svc.cfg.Name } func (svc *Service) IsMaster() (res bool) { return svc.cfg.IsMaster } func (svc *Service) GetAuthKey() (res string) { return svc.cfg.AuthKey } func (svc *Service) GetMaxRunners() (res int) { return svc.cfg.MaxRunners } func (svc *Service) GetConfigPath() (path string) { return svc.path } func (svc *Service) SetConfigPath(path string) { svc.path = path } func newNodeConfigService() (svc2 interfaces.NodeConfigService, err error) { // cfg cfg := NewConfig(nil) // config service svc := &Service{ cfg: cfg, } // normalize config path cfgPath := config.GetConfigPath() svc.SetConfigPath(cfgPath) // init if err := svc.Init(); err != nil { return nil, err } return svc, nil } var _service interfaces.NodeConfigService var _serviceOnce = new(sync.Once) func GetNodeConfigService() interfaces.NodeConfigService { _serviceOnce.Do(func() { var err error _service, err = newNodeConfigService() if err != nil { panic(err) } }) return _service } ================================================ FILE: core/node/config/options.go ================================================ package config import ( "github.com/crawlab-team/crawlab/core/interfaces" ) type Option func(svc interfaces.NodeConfigService) func WithConfigPath(path string) Option { return func(svc interfaces.NodeConfigService) { svc.SetConfigPath(path) } } ================================================ FILE: core/node/service/master_service_v2.go ================================================ package service import ( "errors" "github.com/apex/log" "github.com/cenkalti/backoff/v4" config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/grpc/server" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/common" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/notification" "github.com/crawlab-team/crawlab/core/schedule" "github.com/crawlab-team/crawlab/core/system" "github.com/crawlab-team/crawlab/core/task/handler" "github.com/crawlab-team/crawlab/core/task/scheduler" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "sync" "time" ) type MasterServiceV2 struct { // dependencies cfgSvc interfaces.NodeConfigService server *server.GrpcServerV2 schedulerSvc *scheduler.ServiceV2 handlerSvc *handler.ServiceV2 scheduleSvc *schedule.ServiceV2 systemSvc *system.ServiceV2 // settings cfgPath string address interfaces.Address monitorInterval time.Duration stopOnError bool } func (svc *MasterServiceV2) Init() (err error) { // do nothing return nil } func (svc *MasterServiceV2) Start() { // create indexes common.CreateIndexesV2() // start grpc server if err := svc.server.Start(); err != nil { panic(err) } // register to db if err := svc.Register(); err != nil { panic(err) } // start monitoring worker nodes go svc.Monitor() // start task handler go svc.handlerSvc.Start() // start task scheduler go svc.schedulerSvc.Start() // start schedule service go svc.scheduleSvc.Start() // wait for quit signal svc.Wait() // stop svc.Stop() } func (svc *MasterServiceV2) Wait() { utils.DefaultWait() } func (svc *MasterServiceV2) Stop() { _ = svc.server.Stop() log.Infof("master[%s] service has stopped", svc.GetConfigService().GetNodeKey()) } func (svc *MasterServiceV2) Monitor() { log.Infof("master[%s] monitoring started", svc.GetConfigService().GetNodeKey()) // ticker ticker := time.NewTicker(svc.monitorInterval) for { // monitor err := svc.monitor() if err != nil { trace.PrintError(err) if svc.stopOnError { log.Errorf("master[%s] monitor error, now stopping...", svc.GetConfigService().GetNodeKey()) svc.Stop() return } } // wait <-ticker.C } } func (svc *MasterServiceV2) GetConfigService() (cfgSvc interfaces.NodeConfigService) { return svc.cfgSvc } func (svc *MasterServiceV2) GetConfigPath() (path string) { return svc.cfgPath } func (svc *MasterServiceV2) SetConfigPath(path string) { svc.cfgPath = path } func (svc *MasterServiceV2) GetAddress() (address interfaces.Address) { return svc.address } func (svc *MasterServiceV2) SetAddress(address interfaces.Address) { svc.address = address } func (svc *MasterServiceV2) SetMonitorInterval(duration time.Duration) { svc.monitorInterval = duration } func (svc *MasterServiceV2) Register() (err error) { nodeKey := svc.GetConfigService().GetNodeKey() nodeName := svc.GetConfigService().GetNodeName() node, err := service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": nodeKey}, nil) if err != nil && err.Error() == mongo2.ErrNoDocuments.Error() { // not exists log.Infof("master[%s] does not exist in db", nodeKey) node := models2.NodeV2{ Key: nodeKey, Name: nodeName, MaxRunners: config.DefaultConfigOptions.MaxRunners, IsMaster: true, Status: constants.NodeStatusOnline, Enabled: true, Active: true, ActiveAt: time.Now(), } node.SetCreated(primitive.NilObjectID) node.SetUpdated(primitive.NilObjectID) id, err := service.NewModelServiceV2[models2.NodeV2]().InsertOne(node) if err != nil { return err } log.Infof("added master[%s] in db. id: %s", nodeKey, id.Hex()) return nil } else if err == nil { // exists log.Infof("master[%s] exists in db", nodeKey) node.Status = constants.NodeStatusOnline node.Active = true node.ActiveAt = time.Now() err = service.NewModelServiceV2[models2.NodeV2]().ReplaceById(node.Id, *node) if err != nil { return err } log.Infof("updated master[%s] in db. id: %s", nodeKey, node.Id.Hex()) return nil } else { // error return err } } func (svc *MasterServiceV2) StopOnError() { svc.stopOnError = true } func (svc *MasterServiceV2) GetServer() (svr interfaces.GrpcServer) { return svc.server } func (svc *MasterServiceV2) monitor() (err error) { // update master node status in db if err := svc.updateMasterNodeStatus(); err != nil { if err.Error() == mongo2.ErrNoDocuments.Error() { return nil } return err } // all worker nodes workerNodes, err := svc.getAllWorkerNodes() if err != nil { return err } // iterate all worker nodes wg := sync.WaitGroup{} wg.Add(len(workerNodes)) for _, n := range workerNodes { go func(n *models2.NodeV2) { defer wg.Done() // subscribe ok := svc.subscribeNode(n) if !ok { go svc.setWorkerNodeOffline(n) return } // ping client ok = svc.pingNodeClient(n) if !ok { go svc.setWorkerNodeOffline(n) return } // update node available runners if err := svc.updateNodeAvailableRunners(n); err != nil { trace.PrintError(err) return } }(&n) } wg.Wait() return nil } func (svc *MasterServiceV2) getAllWorkerNodes() (nodes []models2.NodeV2, err error) { query := bson.M{ "key": bson.M{"$ne": svc.cfgSvc.GetNodeKey()}, // not self "active": true, // active } nodes, err = service.NewModelServiceV2[models2.NodeV2]().GetMany(query, nil) if err != nil { if errors.Is(err, mongo2.ErrNoDocuments) { return nil, nil } return nil, trace.TraceError(err) } return nodes, nil } func (svc *MasterServiceV2) updateMasterNodeStatus() (err error) { nodeKey := svc.GetConfigService().GetNodeKey() node, err := service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": nodeKey}, nil) if err != nil { return err } oldStatus := node.Status node.Status = constants.NodeStatusOnline node.Active = true node.ActiveAt = time.Now() newStatus := node.Status err = service.NewModelServiceV2[models2.NodeV2]().ReplaceById(node.Id, *node) if err != nil { return err } if utils.IsPro() { if oldStatus != newStatus { go svc.sendNotification(node) } } return nil } func (svc *MasterServiceV2) setWorkerNodeOffline(node *models2.NodeV2) { node.Status = constants.NodeStatusOffline node.Active = false err := backoff.Retry(func() error { return service.NewModelServiceV2[models2.NodeV2]().ReplaceById(node.Id, *node) }, backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), 3)) if err != nil { trace.PrintError(err) } svc.sendNotification(node) } func (svc *MasterServiceV2) subscribeNode(n *models2.NodeV2) (ok bool) { _, err := svc.server.GetSubscribe("node:" + n.Key) if err != nil { log.Errorf("cannot subscribe worker node[%s]: %v", n.Key, err) return false } return true } func (svc *MasterServiceV2) pingNodeClient(n *models2.NodeV2) (ok bool) { if err := svc.server.SendStreamMessage("node:"+n.Key, grpc.StreamMessageCode_PING); err != nil { log.Errorf("cannot ping worker node client[%s]: %v", n.Key, err) return false } return true } func (svc *MasterServiceV2) updateNodeAvailableRunners(node *models2.NodeV2) (err error) { query := bson.M{ "node_id": node.Id, "status": constants.TaskStatusRunning, } runningTasksCount, err := service.NewModelServiceV2[models2.TaskV2]().Count(query) if err != nil { return trace.TraceError(err) } node.AvailableRunners = node.MaxRunners - runningTasksCount err = service.NewModelServiceV2[models2.NodeV2]().ReplaceById(node.Id, *node) if err != nil { return err } return nil } func (svc *MasterServiceV2) sendNotification(node *models2.NodeV2) { if !utils.IsPro() { return } go notification.GetNotificationServiceV2().SendNodeNotification(node) } func newMasterServiceV2() (res *MasterServiceV2, err error) { // master service svc := &MasterServiceV2{ cfgPath: config2.GetConfigPath(), monitorInterval: 15 * time.Second, stopOnError: false, } // node config service svc.cfgSvc = config.GetNodeConfigService() // grpc server svc.server, err = server.GetGrpcServerV2() if err != nil { return nil, err } // scheduler service svc.schedulerSvc, err = scheduler.GetTaskSchedulerServiceV2() if err != nil { return nil, err } // handler service svc.handlerSvc, err = handler.GetTaskHandlerServiceV2() if err != nil { return nil, err } // schedule service svc.scheduleSvc, err = schedule.GetScheduleServiceV2() if err != nil { return nil, err } // system service svc.systemSvc = system.GetSystemServiceV2() // init if err := svc.Init(); err != nil { return nil, err } return svc, nil } var masterServiceV2 *MasterServiceV2 var masterServiceV2Once = new(sync.Once) func GetMasterServiceV2() (res *MasterServiceV2, err error) { masterServiceV2Once.Do(func() { masterServiceV2, err = newMasterServiceV2() if err != nil { log.Errorf("failed to get master service: %v", err) } }) return masterServiceV2, err } ================================================ FILE: core/node/service/options.go ================================================ package service import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Option func(svc interfaces.NodeService) func WithConfigPath(path string) Option { return func(svc interfaces.NodeService) { svc.SetConfigPath(path) } } func WithAddress(address interfaces.Address) Option { return func(svc interfaces.NodeService) { svc.SetAddress(address) } } func WithMonitorInterval(duration time.Duration) Option { return func(svc interfaces.NodeService) { svc2, ok := svc.(interfaces.NodeMasterService) if ok { svc2.SetMonitorInterval(duration) } } } func WithStopOnError() Option { return func(svc interfaces.NodeService) { svc2, ok := svc.(interfaces.NodeMasterService) if ok { svc2.StopOnError() } } } func WithHeartbeatInterval(duration time.Duration) Option { return func(svc interfaces.NodeService) { svc2, ok := svc.(interfaces.NodeWorkerService) if ok { svc2.SetHeartbeatInterval(duration) } } } ================================================ FILE: core/node/service/worker_service_v2.go ================================================ package service import ( "context" "encoding/json" "github.com/apex/log" config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/grpc/client" "github.com/crawlab-team/crawlab/core/interfaces" client2 "github.com/crawlab-team/crawlab/core/models/client" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/task/handler" "github.com/crawlab-team/crawlab/core/utils" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "sync" "time" ) type WorkerServiceV2 struct { // dependencies cfgSvc interfaces.NodeConfigService client *client.GrpcClientV2 handlerSvc *handler.ServiceV2 // settings cfgPath string address interfaces.Address heartbeatInterval time.Duration // internals n *models2.NodeV2 s grpc.NodeService_SubscribeClient } func (svc *WorkerServiceV2) Init() (err error) { // do nothing return nil } func (svc *WorkerServiceV2) Start() { // start grpc client if err := svc.client.Start(); err != nil { panic(err) } // register to master svc.Register() // start receiving stream messages go svc.Recv() // start sending heartbeat to master go svc.ReportStatus() // start handler go svc.handlerSvc.Start() // wait for quit signal svc.Wait() // stop svc.Stop() } func (svc *WorkerServiceV2) Wait() { utils.DefaultWait() } func (svc *WorkerServiceV2) Stop() { _ = svc.client.Stop() log.Infof("worker[%s] service has stopped", svc.cfgSvc.GetNodeKey()) } func (svc *WorkerServiceV2) Register() { ctx, cancel := svc.client.Context() defer cancel() _, err := svc.client.NodeClient.Register(ctx, &grpc.NodeServiceRegisterRequest{ Key: svc.cfgSvc.GetNodeKey(), Name: svc.cfgSvc.GetNodeName(), IsMaster: svc.cfgSvc.IsMaster(), AuthKey: svc.cfgSvc.GetAuthKey(), MaxRunners: int32(svc.cfgSvc.GetMaxRunners()), }) if err != nil { panic(err) } svc.n, err = client2.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": svc.GetConfigService().GetNodeKey()}, nil) if err != nil { panic(err) } log.Infof("worker[%s] registered to master. id: %s", svc.GetConfigService().GetNodeKey(), svc.n.Id.Hex()) return } func (svc *WorkerServiceV2) Recv() { msgCh := svc.client.GetMessageChannel() for { // return if client is closed if svc.client.IsClosed() { return } // receive message from channel msg := <-msgCh // handle message if err := svc.handleStreamMessage(msg); err != nil { continue } } } func (svc *WorkerServiceV2) handleStreamMessage(msg *grpc.StreamMessage) (err error) { log.Debugf("[WorkerServiceV2] handle msg: %v", msg) switch msg.Code { case grpc.StreamMessageCode_PING: _, err := svc.client.NodeClient.SendHeartbeat(context.Background(), &grpc.NodeServiceSendHeartbeatRequest{ Key: svc.cfgSvc.GetNodeKey(), }) if err != nil { return trace.TraceError(err) } case grpc.StreamMessageCode_RUN_TASK: var t models.Task if err := json.Unmarshal(msg.Data, &t); err != nil { return trace.TraceError(err) } if err := svc.handlerSvc.Run(t.Id); err != nil { return trace.TraceError(err) } case grpc.StreamMessageCode_CANCEL_TASK: var t models.Task if err := json.Unmarshal(msg.Data, &t); err != nil { return trace.TraceError(err) } if err := svc.handlerSvc.Cancel(t.Id); err != nil { return trace.TraceError(err) } } return nil } func (svc *WorkerServiceV2) ReportStatus() { ticker := time.NewTicker(svc.heartbeatInterval) for { // return if client is closed if svc.client.IsClosed() { ticker.Stop() return } // report status svc.reportStatus() // sleep <-ticker.C } } func (svc *WorkerServiceV2) GetConfigService() (cfgSvc interfaces.NodeConfigService) { return svc.cfgSvc } func (svc *WorkerServiceV2) GetConfigPath() (path string) { return svc.cfgPath } func (svc *WorkerServiceV2) SetConfigPath(path string) { svc.cfgPath = path } func (svc *WorkerServiceV2) GetAddress() (address interfaces.Address) { return svc.address } func (svc *WorkerServiceV2) SetAddress(address interfaces.Address) { svc.address = address } func (svc *WorkerServiceV2) SetHeartbeatInterval(duration time.Duration) { svc.heartbeatInterval = duration } func (svc *WorkerServiceV2) reportStatus() { ctx, cancel := context.WithTimeout(context.Background(), svc.heartbeatInterval) defer cancel() _, err := svc.client.NodeClient.SendHeartbeat(ctx, &grpc.NodeServiceSendHeartbeatRequest{ Key: svc.cfgSvc.GetNodeKey(), }) if err != nil { trace.PrintError(err) } } var workerServiceV2 *WorkerServiceV2 var workerServiceV2Once = new(sync.Once) func newWorkerServiceV2() (res *WorkerServiceV2, err error) { svc := &WorkerServiceV2{ cfgPath: config2.GetConfigPath(), heartbeatInterval: 15 * time.Second, } // dependency options var clientOpts []client.Option if svc.address != nil { clientOpts = append(clientOpts, client.WithAddress(svc.address)) } // node config service svc.cfgSvc = nodeconfig.GetNodeConfigService() // grpc client svc.client = client.GetGrpcClientV2() // handler service svc.handlerSvc, err = handler.GetTaskHandlerServiceV2() if err != nil { return nil, err } // init err = svc.Init() if err != nil { return nil, err } return svc, nil } func GetWorkerServiceV2() (res *WorkerServiceV2, err error) { workerServiceV2Once.Do(func() { workerServiceV2, err = newWorkerServiceV2() if err != nil { log.Errorf("failed to get worker service: %v", err) } }) return workerServiceV2, err } ================================================ FILE: core/notification/constants.go ================================================ package notification const ( TypeMail = "mail" TypeIM = "im" ) const ( ChannelMailProviderGmail = "gmail" ChannelMailProviderOutlook = "outlook" ChannelMailProviderYahoo = "yahoo" ChannelMailProviderICloud = "icloud" ChannelMailProviderAol = "aol" ChannelMailProviderZoho = "zoho" ChannelMailProviderQQ = "qq" ChannelMailProvider163 = "163" ChannelMailProviderExmail = "exmail" ChannelIMProviderSlack = "slack" // https://api.slack.com/messaging/webhooks ChannelIMProviderTelegram = "telegram" // https://core.telegram.org/bots/api ChannelIMProviderDiscord = "discord" // https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks ChannelIMProviderMSTeams = "ms_teams" // https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cjavascript ChannelIMProviderWechatWork = "wechat_work" // https://developer.work.weixin.qq.com/document/path/91770 ChannelIMProviderDingtalk = "dingtalk" // https://open.dingtalk.com/document/orgapp/custom-robot-access ChannelIMProviderLark = "lark" // https://www.larksuite.com/hc/en-US/articles/099698615114-use-webhook-triggers ) const ( StatusSending = "sending" StatusSuccess = "success" StatusError = "error" ) ================================================ FILE: core/notification/entity.go ================================================ package notification import "github.com/crawlab-team/crawlab/core/models/models/v2" type VariableData struct { Task *models.TaskV2 `json:"task"` TaskStat *models.TaskStatV2 `json:"task_stat"` Spider *models.SpiderV2 `json:"spider"` Node *models.NodeV2 `json:"node"` Schedule *models.ScheduleV2 `json:"schedule"` Alert *models.NotificationAlertV2 `json:"alert"` Metric *models.MetricV2 `json:"metric"` } ================================================ FILE: core/notification/im.go ================================================ package notification import ( "errors" "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/trace" "github.com/imroc/req" "regexp" "strings" ) type ResBody struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` } func SendIMNotification(ch *models.NotificationChannelV2, title, content string) error { switch ch.Provider { case ChannelIMProviderLark: return sendIMLark(ch, title, content) case ChannelIMProviderDingtalk: return sendIMDingTalk(ch, title, content) case ChannelIMProviderWechatWork: return sendIMWechatWork(ch, title, content) case ChannelIMProviderSlack: return sendIMSlack(ch, title, content) case ChannelIMProviderTelegram: return sendIMTelegram(ch, title, content) case ChannelIMProviderDiscord: return sendIMDiscord(ch, title, content) case ChannelIMProviderMSTeams: return sendIMMSTeams(ch, title, content) } // request header header := req.Header{ "Content-Type": "application/json; charset=utf-8", } // request data data := req.Param{ "msgtype": "markdown", "markdown": req.Param{ "title": title, "text": content, "content": content, }, "at": req.Param{ "atMobiles": []string{}, "isAtAll": false, }, "text": content, } if strings.Contains(strings.ToLower(ch.WebhookUrl), "feishu") { data = req.Param{ "msg_type": "text", "content": req.Param{ "text": content, }, } } // perform request res, err := req.Post(ch.WebhookUrl, header, req.BodyJSON(&data)) if err != nil { return trace.TraceError(err) } // parse response var resBody ResBody if err := res.ToJSON(&resBody); err != nil { return trace.TraceError(err) } // validate response code if resBody.ErrCode != 0 { return errors.New(resBody.ErrMsg) } return nil } func getIMRequestHeader() req.Header { return req.Header{ "Content-Type": "application/json; charset=utf-8", } } func performIMRequest(webhookUrl string, data req.Param) (res *req.Resp, err error) { // perform request res, err = req.Post(webhookUrl, getIMRequestHeader(), req.BodyJSON(&data)) if err != nil { log.Errorf("IM request error: %v", err) return nil, err } // get response response := res.Response() // check status code if response.StatusCode >= 400 { log.Errorf("IM response status code: %d", res.Response().StatusCode) return nil, errors.New(fmt.Sprintf("IM error response %d: %s", response.StatusCode, res.String())) } return res, nil } func performIMRequestWithJson[T any](webhookUrl string, data req.Param) (resBody T, err error) { res, err := performIMRequest(webhookUrl, data) if err != nil { return resBody, err } // parse response if err := res.ToJSON(&resBody); err != nil { log.Warnf("Parsing IM response error: %v", err) resText, err := res.ToString() if err != nil { log.Warnf("Converting response to string error: %v", err) return resBody, err } log.Infof("IM response: %s", resText) return resBody, nil } return resBody, nil } func convertMarkdownToSlack(markdown string) string { // Convert bold text reBold := regexp.MustCompile(`\*\*(.*?)\*\*`) slack := reBold.ReplaceAllString(markdown, `*$1*`) // Convert italic text reItalic := regexp.MustCompile(`\*(.*?)\*`) slack = reItalic.ReplaceAllString(slack, `_$1_`) // Convert links reLink := regexp.MustCompile(`\[(.*?)\]\((.*?)\)`) slack = reLink.ReplaceAllString(slack, `<$2|$1>`) // Convert inline code reInlineCode := regexp.MustCompile("`(.*?)`") slack = reInlineCode.ReplaceAllString(slack, "`$1`") // Convert unordered list slack = strings.ReplaceAll(slack, "- ", "• ") // Convert ordered list reOrderedList := regexp.MustCompile(`^\d+\. `) slack = reOrderedList.ReplaceAllStringFunc(slack, func(s string) string { return strings.Replace(s, ". ", ". ", 1) }) // Convert blockquote reBlockquote := regexp.MustCompile(`^> (.*)`) slack = reBlockquote.ReplaceAllString(slack, `> $1`) return slack } func convertMarkdownToTelegram(markdownText string) string { // Combined regex to handle bold and italic re := regexp.MustCompile(`(?m)(\*\*)(.*)(\*\*)|(__)(.*)(__)|(\*)(.*)(\*)|(_)(.*)(_)`) markdownText = re.ReplaceAllStringFunc(markdownText, func(match string) string { groups := re.FindStringSubmatch(match) if groups[1] != "" || groups[4] != "" { // Handle bold return "*" + match[2:len(match)-2] + "*" } else if groups[6] != "" || groups[9] != "" { // Handle italic return "_" + match[1:len(match)-1] + "_" } else { // No match return match } }) // Convert unordered list re = regexp.MustCompile(`(?m)^- (.*)`) markdownText = re.ReplaceAllString(markdownText, "• $1") // Escape characters escapeChars := []string{"#", "-", "."} for _, c := range escapeChars { markdownText = strings.ReplaceAll(markdownText, c, "\\"+c) } return markdownText } func sendIMLark(ch *models.NotificationChannelV2, title, content string) error { data := req.Param{ "msg_type": "interactive", "card": req.Param{ "header": req.Param{ "title": req.Param{ "tag": "plain_text", "content": title, }, }, "elements": []req.Param{ { "tag": "markdown", "content": content, }, }, }, } resBody, err := performIMRequestWithJson[ResBody](ch.WebhookUrl, data) if err != nil { return err } if resBody.ErrCode != 0 { return errors.New(resBody.ErrMsg) } return nil } func sendIMDingTalk(ch *models.NotificationChannelV2, title string, content string) error { data := req.Param{ "msgtype": "markdown", "markdown": req.Param{ "title": title, "text": fmt.Sprintf("# %s\n\n%s", title, content), }, } resBody, err := performIMRequestWithJson[ResBody](ch.WebhookUrl, data) if err != nil { return err } if resBody.ErrCode != 0 { return errors.New(resBody.ErrMsg) } return nil } func sendIMWechatWork(ch *models.NotificationChannelV2, title string, content string) error { data := req.Param{ "msgtype": "markdown", "markdown": req.Param{ "content": fmt.Sprintf("# %s\n\n%s", title, content), }, } resBody, err := performIMRequestWithJson[ResBody](ch.WebhookUrl, data) if err != nil { return err } if resBody.ErrCode != 0 { return errors.New(resBody.ErrMsg) } return nil } func sendIMSlack(ch *models.NotificationChannelV2, title, content string) error { data := req.Param{ "blocks": []req.Param{ {"type": "header", "text": req.Param{"type": "plain_text", "text": title}}, {"type": "section", "text": req.Param{"type": "mrkdwn", "text": convertMarkdownToSlack(content)}}, }, } _, err := performIMRequest(ch.WebhookUrl, data) if err != nil { return err } return nil } func sendIMTelegram(ch *models.NotificationChannelV2, title string, content string) error { type ResBody struct { Ok bool `json:"ok"` Description string `json:"description"` } // chat id chatId := ch.TelegramChatId if !strings.HasPrefix("@", ch.TelegramChatId) { chatId = fmt.Sprintf("@%s", ch.TelegramChatId) } // webhook url webhookUrl := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", ch.TelegramBotToken) // original Markdown text text := fmt.Sprintf("**%s**\n\n%s", title, content) // convert to Telegram MarkdownV2 text = convertMarkdownToTelegram(text) // request data data := req.Param{ "chat_id": chatId, "text": text, "parse_mode": "MarkdownV2", } // perform request _, err := performIMRequest(webhookUrl, data) if err != nil { return err } return nil } func sendIMDiscord(ch *models.NotificationChannelV2, title string, content string) error { data := req.Param{ "embeds": []req.Param{ { "title": title, "description": content, }, }, } _, err := performIMRequest(ch.WebhookUrl, data) if err != nil { return err } return nil } func sendIMMSTeams(ch *models.NotificationChannelV2, title string, content string) error { data := req.Param{ "type": "message", "attachments": []req.Param{{ "contentType": "application/vnd.microsoft.card.adaptive", "contentUrl": nil, "content": req.Param{ "$schema": "https://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.2", "body": []req.Param{ { "type": "TextBlock", "text": fmt.Sprintf("**%s**", title), "size": "Large", }, { "type": "TextBlock", "text": content, }, }, }, }}, } _, err := performIMRequest(ch.WebhookUrl, data) if err != nil { return err } return nil } ================================================ FILE: core/notification/mail.go ================================================ package notification import ( "errors" "github.com/PuerkitoBio/goquery" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/trace" "gopkg.in/gomail.v2" "net/mail" "regexp" "strings" ) func SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, to, cc, bcc []string, title, content string) error { // sender email senderEmail := ch.SMTPUsername if s.UseCustomSenderEmail { senderEmail = s.SenderEmail } // config smtpConfig := smtpAuthentication{ Server: ch.SMTPServer, Port: ch.SMTPPort, SenderIdentity: s.SenderName, SenderEmail: senderEmail, SMTPUser: ch.SMTPUsername, SMTPPassword: ch.SMTPPassword, } options := sendOptions{ Subject: title, To: to, Cc: cc, Bcc: bcc, } // convert html to text text := content if isHtml(text) { text = convertHtmlToText(text) } // apply theme if isHtml(content) { content = GetTheme() + content } switch ch.Provider { case ChannelMailProviderGmail: return sendMailGmail(ch, smtpConfig, options, content, text) default: return sendMail(smtpConfig, options, content, text) } } func isHtml(content string) bool { regex := regexp.MustCompile(`(?i)<\s*(html|head|body|div|span|p|a|img|table|tr|td|th|tbody|thead|tfoot|ul|ol|li|dl|dt|dd|form|input|textarea|button|select|option|optgroup|fieldset|legend|label|iframe|embed|object|param|video|audio|source|canvas|svg|math|style|link|script|meta|base|title|br|hr|b|strong|i|em|u|s|strike|del|ins|mark|small|sub|sup|big|pre|code|q|blockquote|abbr|address|bdo|cite|dfn|kbd|var|samp|ruby|rt|rp|time|progress|meter|output|area|map)`) return regex.MatchString(content) } func convertHtmlToText(content string) string { doc, err := goquery.NewDocumentFromReader(strings.NewReader(content)) if err != nil { log.Errorf("failed to convert html to text: %v", err) trace.PrintError(err) return "" } return doc.Text() } 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 { Subject string To []string Cc []string Bcc []string } func getMailMessage(smtpConfig smtpAuthentication, options sendOptions, htmlBody string, txtBody string) (m *gomail.Message, err error) { if len(options.To) == 0 { return nil, errors.New("no receiver emails configured") } // from from := mail.Address{ Name: smtpConfig.SenderIdentity, Address: smtpConfig.SenderEmail, } // message m = gomail.NewMessage() m.SetHeader("From", from.String()) m.SetHeader("To", options.To...) m.SetHeader("Subject", options.Subject) if len(options.Cc) > 0 { m.SetHeader("Cc", options.Cc...) } if len(options.Bcc) > 0 { m.SetHeader("Bcc", options.Bcc...) } m.SetBody("text/plain", txtBody) m.AddAlternative("text/html", htmlBody) return m, nil } // send email func sendMail(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") } m, err := getMailMessage(smtpConfig, options, htmlBody, txtBody) if err != nil { return err } // dialer d := gomail.NewDialer(smtpConfig.Server, smtpConfig.Port, smtpConfig.SMTPUser, smtpConfig.SMTPPassword) return d.DialAndSend(m) } ================================================ FILE: core/notification/mail_gmail.go ================================================ package notification import ( "context" "encoding/base64" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/trace" "golang.org/x/oauth2/google" "google.golang.org/api/gmail/v1" "strings" ) func sendMailGmail(ch *models.NotificationChannelV2, smtpConfig smtpAuthentication, options sendOptions, htmlBody, txtBody string) error { // 读取服务账户 JSON 密钥 b := []byte(ch.GoogleOAuth2Json) // 使用服务账户 JSON 密钥文件创建 JWT 配置 config, err := google.JWTConfigFromJSON(b, gmail.GmailSendScope) if err != nil { log.Errorf("Unable to parse service account key file to config: %v", err) return trace.TraceError(err) } // 使用服务账户的电子邮件地址来模拟用户 config.Subject = ch.SMTPUsername // 创建 Gmail 服务 client := config.Client(context.Background()) srv, err := gmail.New(client) if err != nil { log.Errorf("Unable to create Gmail client: %v", err) return trace.TraceError(err) } // 创建 MIME 邮件 m, err := getMailMessage(smtpConfig, options, htmlBody, txtBody) if err != nil { return err } var buf strings.Builder if _, err := m.WriteTo(&buf); err != nil { log.Errorf("Unable to write message: %v", err) return trace.TraceError(err) } // 将邮件内容进行 base64 编码 gmsg := &gmail.Message{ Raw: base64.URLEncoding.EncodeToString([]byte(buf.String())), } // 发送邮件 _, err = srv.Users.Messages.Send("me", gmsg).Do() if err != nil { log.Errorf("Unable to send email: %v", err) return trace.TraceError(err) } return nil } ================================================ FILE: core/notification/oauth2_gmail.go ================================================ package notification import ( "context" "github.com/apex/log" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "net/smtp" "time" ) // 获取服务账户的OAuth2配置 func getGmailOAuth2Token(oauth2Json string) (token *oauth2.Token, err error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // 读取服务账户 JSON 密钥 b := []byte(oauth2Json) // 使用服务账户 JSON 密钥文件创建 JWT 配置 config, err := google.JWTConfigFromJSON(b, "https://mail.google.com/") if err != nil { log.Errorf("Unable to parse service account key file to config: %v", err) return nil, err } // 使用服务账户的电子邮件和访问令牌 token, err = config.TokenSource(ctx).Token() if err != nil { log.Errorf("Unable to generate token: %v", err) return nil, err } return token, nil } // GmailOAuth2Auth 自定义OAuth2认证 type GmailOAuth2Auth struct { username, accessToken string } func (a *GmailOAuth2Auth) Start(_ *smtp.ServerInfo) (string, []byte, error) { return "XOAUTH2", []byte("user=" + a.username + "\x01auth=Bearer " + a.accessToken + "\x01\x01"), nil } func (a *GmailOAuth2Auth) Next(_ []byte, _ bool) ([]byte, error) { return nil, nil } ================================================ FILE: core/notification/service_v2.go ================================================ package notification import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/trace" "github.com/gomarkdown/markdown" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "regexp" "strings" "sync" "time" ) type ServiceV2 struct { } func (svc *ServiceV2) Send(s *models.NotificationSettingV2, args ...any) { title := s.Title wg := sync.WaitGroup{} wg.Add(len(s.ChannelIds)) for _, chId := range s.ChannelIds { go func(chId primitive.ObjectID) { defer wg.Done() ch, err := service.NewModelServiceV2[models.NotificationChannelV2]().GetById(chId) if err != nil { log.Errorf("[NotificationServiceV2] get channel error: %v", err) return } content := svc.getContent(s, ch, args...) switch ch.Type { case TypeMail: svc.SendMail(s, ch, title, content) case TypeIM: svc.SendIM(s, ch, title, content) } }(chId) } wg.Wait() } func (svc *ServiceV2) SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, title, content string) { mailTo := s.MailTo mailCc := s.MailCc mailBcc := s.MailBcc // request r, _ := svc.createRequest(s, ch, title, content) // send mail err := SendMail(s, ch, mailTo, mailCc, mailBcc, title, content) if err != nil { log.Errorf("[NotificationServiceV2] send mail error: %v", err) } // save request go svc.saveRequest(r, err) } func (svc *ServiceV2) SendIM(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, title, content string) { // request r, _ := svc.createRequest(s, ch, title, content) // send mobile notification err := SendIMNotification(ch, title, content) if err != nil { log.Errorf("[NotificationServiceV2] send mobile notification error: %v", err) } // save request go svc.saveRequest(r, err) } func (svc *ServiceV2) getContent(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, args ...any) (content string) { vd := svc.getVariableData(args...) switch s.TemplateMode { case constants.NotificationTemplateModeMarkdown: variables := svc.parseTemplateVariables(s.TemplateMarkdown) content = svc.geContentWithVariables(s.TemplateMarkdown, variables, vd) if ch.Type == TypeMail { content = svc.convertMarkdownToHtml(content) } return content case constants.NotificationTemplateModeRichText: template := s.TemplateRichText if ch.Type == TypeIM { template = s.TemplateMarkdown } variables := svc.parseTemplateVariables(template) return svc.geContentWithVariables(template, variables, vd) } return content } func (svc *ServiceV2) geContentWithVariables(template string, variables []entity.NotificationVariable, vd VariableData) (content string) { content = template for _, v := range variables { switch v.Category { case "task": if vd.Task == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "id": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Id.Hex()) case "status": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Status) case "cmd": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Cmd) case "param": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Param) case "error": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Error) case "pid": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Task.Pid)) case "type": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Type) case "mode": content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Mode) case "priority": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Task.Priority)) case "created_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Task.CreatedAt)) case "created_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Task.CreatedBy)) case "updated_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Task.UpdatedAt)) case "updated_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Task.UpdatedBy)) } case "task_stat": if vd.TaskStat == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "start_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.TaskStat.StartTs)) case "end_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.TaskStat.EndTs)) case "wait_duration": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%ds", vd.TaskStat.WaitDuration/1000)) case "runtime_duration": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%ds", vd.TaskStat.RuntimeDuration/1000)) case "total_duration": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%ds", vd.TaskStat.TotalDuration/1000)) case "result_count": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.TaskStat.ResultCount)) } case "spider": if vd.Spider == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "id": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Id.Hex()) case "name": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Name) case "description": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Description) case "mode": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Mode) case "cmd": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Cmd) case "param": content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Param) case "priority": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Spider.Priority)) case "created_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Spider.CreatedAt)) case "created_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Spider.CreatedBy)) case "updated_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Spider.UpdatedAt)) case "updated_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Spider.UpdatedBy)) } case "node": if vd.Node == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "id": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Id.Hex()) case "key": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Key) case "name": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Name) case "is_master": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Node.IsMaster)) case "ip": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Ip) case "mac": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Mac) case "hostname": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Hostname) case "description": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Description) case "status": content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Status) case "enabled": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Node.Enabled)) case "active": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Node.Active)) case "active_at": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Node.ActiveAt)) case "available_runners": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Node.AvailableRunners)) case "max_runners": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Node.MaxRunners)) case "created_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Node.CreatedAt)) case "created_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Node.CreatedBy)) case "updated_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Node.UpdatedAt)) case "updated_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Node.UpdatedBy)) } case "schedule": if vd.Schedule == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "id": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Id.Hex()) case "name": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Name) case "description": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Description) case "cron": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Cron) case "cmd": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Cmd) case "param": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Param) case "mode": content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Mode) case "priority": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Schedule.Priority)) case "enabled": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Schedule.Enabled)) case "created_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Schedule.CreatedAt)) case "created_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Schedule.CreatedBy)) case "updated_ts": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTime(vd.Schedule.UpdatedAt)) case "updated_by": content = strings.ReplaceAll(content, v.GetKey(), svc.getUsernameById(vd.Schedule.UpdatedBy)) } case "alert": switch v.Name { case "id": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.Id.Hex()) case "name": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.Name) case "description": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.Description) case "enabled": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Alert.Enabled)) case "metric_name": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.MetricName) case "operator": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.Operator) case "lasting_seconds": content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Alert.LastingSeconds)) case "target_value": content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedTargetValue(vd.Alert)) case "level": content = strings.ReplaceAll(content, v.GetKey(), vd.Alert.Level) } case "metric": if vd.Metric == nil { content = strings.ReplaceAll(content, v.GetKey(), "N/A") continue } switch v.Name { case "type": content = strings.ReplaceAll(content, v.GetKey(), vd.Metric.Type) case "node_id": content = strings.ReplaceAll(content, v.GetKey(), vd.Metric.NodeId.Hex()) default: content = strings.ReplaceAll(content, v.GetKey(), svc.getFormattedMetricValue(v.Name, vd.Metric)) } } } return content } func (svc *ServiceV2) getVariableData(args ...any) (vd VariableData) { for _, arg := range args { switch arg.(type) { case *models.TaskV2: vd.Task = arg.(*models.TaskV2) case *models.TaskStatV2: vd.TaskStat = arg.(*models.TaskStatV2) case *models.SpiderV2: vd.Spider = arg.(*models.SpiderV2) case *models.NodeV2: vd.Node = arg.(*models.NodeV2) case *models.ScheduleV2: vd.Schedule = arg.(*models.ScheduleV2) case *models.NotificationAlertV2: vd.Alert = arg.(*models.NotificationAlertV2) case *models.MetricV2: vd.Metric = arg.(*models.MetricV2) } } return vd } func (svc *ServiceV2) parseTemplateVariables(template string) (variables []entity.NotificationVariable) { // regex pattern regex := regexp.MustCompile("\\$\\{(\\w+):(\\w+)}") // find all matches matches := regex.FindAllStringSubmatch(template, -1) // variables map variablesMap := make(map[string]entity.NotificationVariable) // iterate over matches for _, match := range matches { variable := entity.NotificationVariable{ Category: match[1], Name: match[2], } key := fmt.Sprintf("%s:%s", variable.Category, variable.Name) if _, ok := variablesMap[key]; !ok { variablesMap[key] = variable } } // convert map to slice for _, variable := range variablesMap { variables = append(variables, variable) } return variables } func (svc *ServiceV2) getUsernameById(id primitive.ObjectID) (username string) { if id.IsZero() { return "" } u, err := service.NewModelServiceV2[models.UserV2]().GetById(id) if err != nil { log.Errorf("[NotificationServiceV2] get user error: %v", err) return "" } return u.Username } func (svc *ServiceV2) getFormattedTime(t time.Time) (res string) { if t.IsZero() { return "N/A" } return t.Local().Format(time.DateTime) } func (svc *ServiceV2) getFormattedTargetValue(a *models.NotificationAlertV2) (res string) { if strings.HasSuffix(a.MetricName, "_percent") { return fmt.Sprintf("%.2f%%", a.TargetValue) } else if strings.HasSuffix(a.MetricName, "_memory") { return fmt.Sprintf("%dMB", int(a.TargetValue/(1024*1024))) } else if strings.HasSuffix(a.MetricName, "_disk") { return fmt.Sprintf("%dGB", int(a.TargetValue/(1024*1024*1024))) } else if strings.HasSuffix(a.MetricName, "_rate") { return fmt.Sprintf("%.2fMB/s", a.TargetValue/(1024*1024)) } else { return fmt.Sprintf("%f", a.TargetValue) } } func (svc *ServiceV2) getFormattedMetricValue(metricName string, m *models.MetricV2) (res string) { switch metricName { case "cpu_usage_percent": return fmt.Sprintf("%.2f%%", m.CpuUsagePercent) case "total_memory": return fmt.Sprintf("%dMB", m.TotalMemory/(1024*1024)) case "available_memory": return fmt.Sprintf("%dMB", m.AvailableMemory/(1024*1024)) case "used_memory": return fmt.Sprintf("%dMB", m.UsedMemory/(1024*1024)) case "used_memory_percent": return fmt.Sprintf("%.2f%%", m.UsedMemoryPercent) case "total_disk": return fmt.Sprintf("%dGB", m.TotalDisk/(1024*1024*1024)) case "available_disk": return fmt.Sprintf("%dGB", m.AvailableDisk/(1024*1024*1024)) case "used_disk": return fmt.Sprintf("%dGB", m.UsedDisk/(1024*1024*1024)) case "used_disk_percent": return fmt.Sprintf("%.2f%%", m.UsedDiskPercent) case "disk_read_bytes_rate": return fmt.Sprintf("%.2fMB/s", m.DiskReadBytesRate/(1024*1024)) case "disk_write_bytes_rate": return fmt.Sprintf("%.2fMB/s", m.DiskWriteBytesRate/(1024*1024)) case "network_bytes_sent_rate": return fmt.Sprintf("%.2fMB/s", m.NetworkBytesSentRate/(1024*1024)) case "network_bytes_recv_rate": return fmt.Sprintf("%.2fMB/s", m.NetworkBytesRecvRate/(1024*1024)) default: return "N/A" } } func (svc *ServiceV2) convertMarkdownToHtml(content string) (html string) { return string(markdown.ToHTML([]byte(content), nil, nil)) } func (svc *ServiceV2) SendNodeNotification(node *models.NodeV2) { // arguments var args []any args = append(args, node) // settings settings, err := service.NewModelServiceV2[models.NotificationSettingV2]().GetMany(bson.M{ "enabled": true, "trigger": bson.M{ "$regex": constants.NotificationTriggerPatternNode, }, }, nil) if err != nil { log.Errorf("get notification settings error: %v", err) trace.PrintError(err) return } for _, s := range settings { // send notification switch s.Trigger { case constants.NotificationTriggerNodeStatusChange: go svc.Send(&s, args...) case constants.NotificationTriggerNodeOnline: if node.Status == constants.NodeStatusOnline { go svc.Send(&s, args...) } case constants.NotificationTriggerNodeOffline: if node.Status == constants.NodeStatusOffline { go svc.Send(&s, args...) } } } } func (svc *ServiceV2) createRequest(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, title, content string) (res *models.NotificationRequestV2, err error) { senderEmail := ch.SMTPUsername if s.UseCustomSenderEmail { senderEmail = s.SenderEmail } r := models.NotificationRequestV2{ Status: StatusSending, SettingId: s.Id, ChannelId: ch.Id, Title: title, Content: content, SenderEmail: senderEmail, SenderName: s.SenderName, MailTo: s.MailTo, MailCc: s.MailCc, MailBcc: s.MailBcc, } r.SetCreatedAt(time.Now()) r.SetUpdatedAt(time.Now()) r.Id, err = service.NewModelServiceV2[models.NotificationRequestV2]().InsertOne(r) if err != nil { log.Errorf("[NotificationServiceV2] save request error: %v", err) return nil, err } return &r, nil } func (svc *ServiceV2) saveRequest(r *models.NotificationRequestV2, err error) { if r == nil { return } if err != nil { r.Status = StatusError r.Error = err.Error() } else { r.Status = StatusSuccess } r.SetUpdatedAt(time.Now()) err = service.NewModelServiceV2[models.NotificationRequestV2]().ReplaceById(r.Id, *r) if err != nil { log.Errorf("[NotificationServiceV2] save request error: %v", err) } } func newNotificationServiceV2() *ServiceV2 { return &ServiceV2{} } var _serviceV2 *ServiceV2 var _serviceV2Once = new(sync.Once) func GetNotificationServiceV2() *ServiceV2 { _serviceV2Once.Do(func() { _serviceV2 = newNotificationServiceV2() }) return _serviceV2 } ================================================ FILE: core/notification/service_v2_test.go ================================================ package notification import ( "github.com/crawlab-team/crawlab/core/entity" "testing" "github.com/stretchr/testify/assert" ) func TestParseTemplateVariables_WithValidTemplate_ReturnsVariables(t *testing.T) { svc := ServiceV2{} template := "Dear ${user:name}, your task ${task:id} is ${task:status}." expected := []entity.NotificationVariable{ {Category: "user", Name: "name"}, {Category: "task", Name: "id"}, {Category: "task", Name: "status"}, } variables := svc.parseTemplateVariables(template) // contains all expected variables assert.ElementsMatch(t, expected, variables) } func TestParseTemplateVariables_WithRepeatedVariables_ReturnsUniqueVariables(t *testing.T) { svc := ServiceV2{} template := "Dear ${user:name}, your task ${task:id} is ${task:status}. Again, ${user:name} and ${task:id}." expected := []entity.NotificationVariable{ {Category: "user", Name: "name"}, {Category: "task", Name: "id"}, {Category: "task", Name: "status"}, } variables := svc.parseTemplateVariables(template) // contains all expected variables assert.ElementsMatch(t, expected, variables) } ================================================ FILE: core/notification/theme.go ================================================ package notification const defaultTheme = `` func GetTheme() string { return defaultTheme } ================================================ FILE: core/process/daemon.go ================================================ package process import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/sys_exec" "github.com/crawlab-team/crawlab/trace" "math/rand" "os/exec" "time" ) const ( SignalCreate = iota SignalStart SignalStopped SignalError SignalExited SignalReachedMaxErrors ) type Daemon struct { // settings maxErrors int exitTimeout time.Duration // internals errors int errMsg string exitCode int newCmdFn func() *exec.Cmd cmd *exec.Cmd stopped bool ch chan int } func (d *Daemon) Start() (err error) { go d.handleSignal() for { // command d.cmd = d.newCmdFn() d.ch <- SignalCreate // attempt to run _ = d.cmd.Start() d.ch <- SignalStart if err := d.cmd.Wait(); err != nil { // stopped d.ch <- SignalStopped if d.stopped { log.Infof("daemon stopped") return nil } // error d.ch <- SignalError d.errMsg = err.Error() trace.PrintError(err) } // exited d.ch <- SignalExited // exit code d.exitCode = d.cmd.ProcessState.ExitCode() // check exit code if d.exitCode == 0 { log.Infof("process exited with code 0") return } // error message d.errMsg = errors.ErrorProcessDaemonProcessExited.Error() // increment errors d.errors++ // validate if error count exceeds max errors if d.errors >= d.maxErrors { log.Infof("reached max errors: %d", d.maxErrors) d.ch <- SignalReachedMaxErrors return errors.ErrorProcessReachedMaxErrors } // re-attempt waitSec := rand.Intn(5) log.Infof("re-attempt to start process in %d seconds...", waitSec) time.Sleep(time.Duration(waitSec) * time.Second) } } func (d *Daemon) Stop() { d.stopped = true opts := &sys_exec.KillProcessOptions{ Timeout: d.exitTimeout, Force: false, } _ = sys_exec.KillProcess(d.cmd, opts) } func (d *Daemon) GetMaxErrors() (maxErrors int) { return d.maxErrors } func (d *Daemon) SetMaxErrors(maxErrors int) { d.maxErrors = maxErrors } func (d *Daemon) GetExitTimeout() (timeout time.Duration) { return d.exitTimeout } func (d *Daemon) SetExitTimeout(timeout time.Duration) { d.exitTimeout = timeout } func (d *Daemon) GetCmd() (cmd *exec.Cmd) { return d.cmd } func (d *Daemon) GetCh() (ch chan int) { return d.ch } func (d *Daemon) handleSignal() { for { select { case signal := <-d.ch: switch signal { case SignalCreate: log.Infof("process created") case SignalStart: log.Infof("process started") case SignalStopped: log.Infof("process stopped") case SignalError: trace.PrintError(errors.NewProcessError(d.errMsg)) case SignalExited: log.Infof("process exited") case SignalReachedMaxErrors: log.Infof("reached max errors") return } } } } func NewProcessDaemon(newCmdFn func() *exec.Cmd, opts ...DaemonOption) (d interfaces.ProcessDaemon) { // daemon d = &Daemon{ maxErrors: 5, exitTimeout: 15 * time.Second, errors: 0, errMsg: "", newCmdFn: newCmdFn, stopped: false, ch: make(chan int), } // apply options for _, opt := range opts { opt(d) } return d } ================================================ FILE: core/process/daemon_test.go ================================================ package process import ( "github.com/stretchr/testify/require" "os/exec" "testing" ) func TestDaemon(t *testing.T) { d := NewProcessDaemon(func() *exec.Cmd { return exec.Command("echo", "hello") }) err := d.Start() require.Nil(t, err) d = NewProcessDaemon(func() *exec.Cmd { return exec.Command("return", "1") }) err = d.Start() require.NotNil(t, err) } ================================================ FILE: core/process/manage.go ================================================ package process import ( "github.com/crawlab-team/crawlab/trace" "os/exec" "regexp" "runtime" "strings" ) var pidRegexp, _ = regexp.Compile("(?:^|\\s+)\\d+(?:$|\\s+)") func ProcessIdExists(id int) (ok bool) { lines, err := ListProcess(string(rune(id))) if err != nil { return false } for _, line := range lines { matched := pidRegexp.MatchString(line) if matched { return true } } return false } func ListProcess(text string) (lines []string, err error) { if runtime.GOOS == "windows" { return listProcessWindow(text) } else { return listProcessLinuxMac(text) } } func listProcessWindow(text string) (lines []string, err error) { cmd := exec.Command("tasklist", "/fi", text) out, err := cmd.CombinedOutput() _, ok := err.(*exec.ExitError) if !ok { return nil, trace.TraceError(err) } lines = strings.Split(string(out), "\n") return lines, nil } func listProcessLinuxMac(text string) (lines []string, err error) { cmd := exec.Command("ps", "aux") out, err := cmd.CombinedOutput() _, ok := err.(*exec.ExitError) if !ok { return nil, trace.TraceError(err) } _lines := strings.Split(string(out), "\n") for _, l := range _lines { if strings.Contains(l, text) { lines = append(lines, l) } } return lines, nil } ================================================ FILE: core/process/options.go ================================================ package process import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type DaemonOption func(d interfaces.ProcessDaemon) func WithDaemonMaxErrors(maxErrors int) DaemonOption { return func(d interfaces.ProcessDaemon) { d.SetMaxErrors(maxErrors) } } func WithExitTimeout(timeout time.Duration) DaemonOption { return func(d interfaces.ProcessDaemon) { } } ================================================ FILE: core/result/options.go ================================================ package result import "go.mongodb.org/mongo-driver/bson/primitive" type Option func(opts *Options) type Options struct { registryKey string // registry key SpiderId primitive.ObjectID // data source id } func WithRegistryKey(key string) Option { return func(opts *Options) { opts.registryKey = key } } ================================================ FILE: core/result/service.go ================================================ package result import ( "fmt" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson/primitive" "sync" ) func NewResultService(registryKey string, s *models.Spider) (svc2 interfaces.ResultService, err error) { // result service function var fn interfaces.ResultServiceRegistryFn if registryKey == "" { // default fn = NewResultServiceMongo } else { // from registry reg := GetResultServiceRegistry() fn = reg.Get(registryKey) if fn == nil { return nil, errors.NewResultError(fmt.Sprintf("%s is not implemented", registryKey)) } } // generate result service svc, err := fn(s.ColId, s.DataSourceId) if err != nil { return nil, trace.TraceError(err) } return svc, nil } var store = sync.Map{} func GetResultService(spiderId primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // model service modelSvc, err := service.GetService() if err != nil { return nil, trace.TraceError(err) } // spider s, err := modelSvc.GetSpiderById(spiderId) if err != nil { return nil, trace.TraceError(err) } // store key storeKey := s.ColId.Hex() + ":" + s.DataSourceId.Hex() // attempt to load result service from store res, _ := store.Load(storeKey) if res != nil { svc, ok := res.(interfaces.ResultService) if ok { return svc, nil } } // registry key var registryKey string ds, _ := modelSvc.GetDataSourceById(s.DataSourceId) if ds != nil { registryKey = ds.Type } // create a new result service if not exists svc, err := NewResultService(registryKey, s) if err != nil { return nil, err } // save into store store.Store(storeKey, svc) return svc, nil } ================================================ FILE: core/result/service_mongo.go ================================================ package result import ( "github.com/crawlab-team/crawlab/trace" "time" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type ServiceMongo struct { // dependencies modelSvc service.ModelService modelColSvc interfaces.ModelBaseService // internals colId primitive.ObjectID // _id of models.DataCollection dc *models.DataCollection // models.DataCollection t time.Time } func (svc *ServiceMongo) List(query generic.ListQuery, opts *generic.ListOptions) (results []interface{}, err error) { _query := svc.getQuery(query) _opts := svc.getOpts(opts) return svc.getList(_query, _opts) } func (svc *ServiceMongo) Count(query generic.ListQuery) (n int, err error) { _query := svc.getQuery(query) return svc.modelColSvc.Count(_query) } func (svc *ServiceMongo) Insert(docs ...interface{}) (err error) { if svc.dc.Dedup.Enabled && len(svc.dc.Dedup.Keys) > 0 { for _, doc := range docs { hash, err := utils.GetResultHash(doc, svc.dc.Dedup.Keys) if err != nil { return err } doc.(interfaces.Result).SetValue(constants.HashKey, hash) query := bson.M{constants.HashKey: hash} switch svc.dc.Dedup.Type { case constants.DedupTypeOverwrite: err = mongo.GetMongoCol(svc.dc.Name).ReplaceWithOptions(query, doc, &options.ReplaceOptions{Upsert: &[]bool{true}[0]}) if err != nil { return trace.TraceError(err) } default: var o bson.M err := mongo.GetMongoCol(svc.dc.Name).Find(query, &mongo.FindOptions{Limit: 1}).One(&o) if err == nil { // exists, ignore continue } if err != mongo2.ErrNoDocuments { // error return trace.TraceError(err) } // not exists, insert _, err = mongo.GetMongoCol(svc.dc.Name).Insert(doc) if err != nil { return trace.TraceError(err) } } } } else { _, err = mongo.GetMongoCol(svc.dc.Name).InsertMany(docs) if err != nil { return trace.TraceError(err) } } return nil } func (svc *ServiceMongo) Index(fields []string) { for _, field := range fields { _ = mongo.GetMongoCol(svc.dc.Name).CreateIndex(mongo2.IndexModel{Keys: bson.M{field: 1}}) } } func (svc *ServiceMongo) SetTime(t time.Time) { svc.t = t } func (svc *ServiceMongo) GetTime() (t time.Time) { return svc.t } func (svc *ServiceMongo) getList(query bson.M, opts *mongo.FindOptions) (results []interface{}, err error) { list, err := svc.modelColSvc.GetList(query, opts) if err != nil { return nil, err } for _, d := range list.GetModels() { r, ok := d.(interfaces.Result) if ok { results = append(results, r) } } return results, nil } func (svc *ServiceMongo) getQuery(query generic.ListQuery) (res bson.M) { return utils.GetMongoQuery(query) } func (svc *ServiceMongo) getOpts(opts *generic.ListOptions) (res *mongo.FindOptions) { return utils.GetMongoOpts(opts) } func NewResultServiceMongo(colId primitive.ObjectID, _ primitive.ObjectID) (svc2 interfaces.ResultService, err error) { // service svc := &ServiceMongo{ colId: colId, t: time.Now(), } // dependency injection svc.modelSvc, err = service.GetService() if err != nil { return nil, err } // data collection svc.dc, _ = svc.modelSvc.GetDataCollectionById(colId) go func() { for { time.Sleep(1 * time.Second) svc.dc, _ = svc.modelSvc.GetDataCollectionById(colId) } }() // data collection model service svc.modelColSvc = service.GetBaseServiceByColName(interfaces.ModelIdResult, svc.dc.Name) return svc, nil } ================================================ FILE: core/result/service_registry.go ================================================ package result import ( "github.com/crawlab-team/crawlab/core/interfaces" "sync" ) type ServiceRegistry struct { // internals services sync.Map } func (r *ServiceRegistry) Register(key string, fn interfaces.ResultServiceRegistryFn) { r.services.Store(key, fn) } func (r *ServiceRegistry) Unregister(key string) { r.services.Delete(key) } func (r *ServiceRegistry) Get(key string) (fn interfaces.ResultServiceRegistryFn) { res, ok := r.services.Load(key) if ok { fn, ok = res.(interfaces.ResultServiceRegistryFn) if !ok { return nil } return fn } return nil } func NewResultServiceRegistry() (r interfaces.ResultServiceRegistry) { r = &ServiceRegistry{ services: sync.Map{}, } return r } var _svc interfaces.ResultServiceRegistry func GetResultServiceRegistry() (r interfaces.ResultServiceRegistry) { if _svc != nil { return _svc } _svc = NewResultServiceRegistry() return _svc } ================================================ FILE: core/schedule/logger.go ================================================ package schedule import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/trace" "github.com/robfig/cron/v3" "strings" ) type Logger struct { } func (l *Logger) Info(msg string, keysAndValues ...interface{}) { p := l.getPlaceholder(len(keysAndValues)) log.Infof(fmt.Sprintf("cron: %s %s", msg, p), keysAndValues...) } func (l *Logger) Error(err error, msg string, keysAndValues ...interface{}) { p := l.getPlaceholder(len(keysAndValues)) log.Errorf(fmt.Sprintf("cron: %s %s", msg, p), keysAndValues...) trace.PrintError(err) } func (l *Logger) getPlaceholder(n int) (s string) { var arr []string for i := 0; i < n; i++ { arr = append(arr, "%v") } return strings.Join(arr, " ") } func NewLogger() cron.Logger { return &Logger{} } ================================================ FILE: core/schedule/options.go ================================================ package schedule import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Option func(svc interfaces.ScheduleService) func WithConfigPath(path string) Option { return func(svc interfaces.ScheduleService) { svc.SetConfigPath(path) } } func WithLocation(loc *time.Location) Option { return func(svc interfaces.ScheduleService) { svc.SetLocation(loc) } } func WithDelayIfStillRunning() Option { return func(svc interfaces.ScheduleService) { svc.SetDelay(true) } } func WithSkipIfStillRunning() Option { return func(svc interfaces.ScheduleService) { svc.SetSkip(true) } } func WithUpdateInterval(interval time.Duration) Option { return func(svc interfaces.ScheduleService) { } } ================================================ FILE: core/schedule/service.go ================================================ package schedule import ( "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "sync" "time" ) type Service struct { // dependencies interfaces.WithConfigPath modelSvc service.ModelService adminSvc interfaces.SpiderAdminService // settings variables loc *time.Location delay bool skip bool updateInterval time.Duration // internals cron *cron.Cron logger cron.Logger schedules []models.Schedule stopped bool mu sync.Mutex } func (svc *Service) GetLocation() (loc *time.Location) { return svc.loc } func (svc *Service) SetLocation(loc *time.Location) { svc.loc = loc } func (svc *Service) GetDelay() (delay bool) { return svc.delay } func (svc *Service) SetDelay(delay bool) { svc.delay = delay } func (svc *Service) GetSkip() (skip bool) { return svc.skip } func (svc *Service) SetSkip(skip bool) { svc.skip = skip } func (svc *Service) GetUpdateInterval() (interval time.Duration) { return svc.updateInterval } func (svc *Service) SetUpdateInterval(interval time.Duration) { svc.updateInterval = interval } func (svc *Service) Init() (err error) { return svc.fetch() } func (svc *Service) Start() { svc.cron.Start() go svc.Update() } func (svc *Service) Wait() { utils.DefaultWait() svc.Stop() } func (svc *Service) Stop() { svc.stopped = true svc.cron.Stop() } func (svc *Service) Enable(s interfaces.Schedule, args ...interface{}) (err error) { svc.mu.Lock() defer svc.mu.Unlock() id, err := svc.cron.AddFunc(s.GetCron(), svc.schedule(s.GetId())) if err != nil { return trace.TraceError(err) } s.SetEnabled(true) s.SetEntryId(id) u := utils.GetUserFromArgs(args...) return delegate.NewModelDelegate(s, u).Save() } func (svc *Service) Disable(s interfaces.Schedule, args ...interface{}) (err error) { svc.mu.Lock() defer svc.mu.Unlock() svc.cron.Remove(s.GetEntryId()) s.SetEnabled(false) s.SetEntryId(-1) u := utils.GetUserFromArgs(args...) return delegate.NewModelDelegate(s, u).Save() } func (svc *Service) Update() { for { if svc.stopped { return } svc.update() time.Sleep(svc.updateInterval) } } func (svc *Service) GetCron() (c *cron.Cron) { return svc.cron } func (svc *Service) update() { // fetch enabled schedules if err := svc.fetch(); err != nil { trace.PrintError(err) return } // entry id map entryIdsMap := svc.getEntryIdsMap() // iterate enabled schedules for _, s := range svc.schedules { _, ok := entryIdsMap[s.EntryId] if ok { entryIdsMap[s.EntryId] = true } else { if err := svc.Enable(&s); err != nil { trace.PrintError(err) continue } } } // remove non-existent entries for id, ok := range entryIdsMap { if !ok { svc.cron.Remove(id) } } } func (svc *Service) getEntryIdsMap() (res map[cron.EntryID]bool) { res = map[cron.EntryID]bool{} for _, e := range svc.cron.Entries() { res[e.ID] = false } return res } func (svc *Service) fetch() (err error) { query := bson.M{ "enabled": true, } svc.schedules, err = svc.modelSvc.GetScheduleList(query, nil) if err != nil { return err } return nil } func (svc *Service) schedule(id primitive.ObjectID) (fn func()) { return func() { // schedule s, err := svc.modelSvc.GetScheduleById(id) if err != nil { trace.PrintError(err) return } // spider spider, err := svc.modelSvc.GetSpiderById(s.GetSpiderId()) if err != nil { trace.PrintError(err) return } // options opts := &interfaces.SpiderRunOptions{ Mode: s.GetMode(), NodeIds: s.GetNodeIds(), Cmd: s.GetCmd(), Param: s.GetParam(), Priority: s.GetPriority(), ScheduleId: s.GetId(), UserId: s.UserId, } // normalize options if opts.Mode == "" { opts.Mode = spider.Mode } if len(opts.NodeIds) == 0 { opts.NodeIds = spider.NodeIds } if opts.Cmd == "" { opts.Cmd = spider.Cmd } if opts.Param == "" { opts.Param = spider.Param } if opts.Priority == 0 { if spider.Priority > 0 { opts.Priority = spider.Priority } else { opts.Priority = 5 } } // schedule or assign a task in the task queue if _, err := svc.adminSvc.Schedule(s.GetSpiderId(), opts); err != nil { trace.PrintError(err) } } } func NewScheduleService() (svc2 interfaces.ScheduleService, err error) { // service svc := &Service{ WithConfigPath: config.NewConfigPathService(), loc: time.Local, // TODO: implement delay and skip delay: false, skip: false, updateInterval: 1 * time.Minute, } // dependency injection if err := container.GetContainer().Invoke(func( modelSvc service.ModelService, adminSvc interfaces.SpiderAdminService, ) { svc.modelSvc = modelSvc svc.adminSvc = adminSvc }); err != nil { return nil, trace.TraceError(err) } // logger svc.logger = NewLogger() // cron svc.cron = cron.New( cron.WithLogger(svc.logger), cron.WithLocation(svc.loc), cron.WithChain(cron.Recover(svc.logger)), ) // initialize if err := svc.Init(); err != nil { return nil, err } return svc, nil } var svc interfaces.ScheduleService func GetScheduleService() (res interfaces.ScheduleService, err error) { if svc != nil { return svc, nil } svc, err = NewScheduleService() if err != nil { return nil, err } return svc, nil } ================================================ FILE: core/schedule/service_v2.go ================================================ package schedule import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/spider/admin" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "sync" "time" ) type ServiceV2 struct { // dependencies interfaces.WithConfigPath modelSvc *service.ModelServiceV2[models2.ScheduleV2] adminSvc *admin.ServiceV2 // settings variables loc *time.Location delay bool skip bool updateInterval time.Duration // internals cron *cron.Cron logger cron.Logger schedules []models2.ScheduleV2 stopped bool mu sync.Mutex } func (svc *ServiceV2) GetLocation() (loc *time.Location) { return svc.loc } func (svc *ServiceV2) SetLocation(loc *time.Location) { svc.loc = loc } func (svc *ServiceV2) GetDelay() (delay bool) { return svc.delay } func (svc *ServiceV2) SetDelay(delay bool) { svc.delay = delay } func (svc *ServiceV2) GetSkip() (skip bool) { return svc.skip } func (svc *ServiceV2) SetSkip(skip bool) { svc.skip = skip } func (svc *ServiceV2) GetUpdateInterval() (interval time.Duration) { return svc.updateInterval } func (svc *ServiceV2) SetUpdateInterval(interval time.Duration) { svc.updateInterval = interval } func (svc *ServiceV2) Init() (err error) { return svc.fetch() } func (svc *ServiceV2) Start() { svc.cron.Start() go svc.Update() } func (svc *ServiceV2) Wait() { utils.DefaultWait() svc.Stop() } func (svc *ServiceV2) Stop() { svc.stopped = true svc.cron.Stop() } func (svc *ServiceV2) Enable(s models2.ScheduleV2, by primitive.ObjectID) (err error) { svc.mu.Lock() defer svc.mu.Unlock() id, err := svc.cron.AddFunc(s.Cron, svc.schedule(s.Id)) if err != nil { return trace.TraceError(err) } s.Enabled = true s.EntryId = id s.SetUpdated(by) return svc.modelSvc.ReplaceById(s.Id, s) } func (svc *ServiceV2) Disable(s models2.ScheduleV2, by primitive.ObjectID) (err error) { svc.mu.Lock() defer svc.mu.Unlock() svc.cron.Remove(s.EntryId) s.Enabled = false s.EntryId = -1 s.SetUpdated(by) return svc.modelSvc.ReplaceById(s.Id, s) } func (svc *ServiceV2) Update() { for { if svc.stopped { return } svc.update() time.Sleep(svc.updateInterval) } } func (svc *ServiceV2) GetCron() (c *cron.Cron) { return svc.cron } func (svc *ServiceV2) update() { // fetch enabled schedules if err := svc.fetch(); err != nil { trace.PrintError(err) return } // entry id map entryIdsMap := svc.getEntryIdsMap() // iterate enabled schedules for _, s := range svc.schedules { _, ok := entryIdsMap[s.EntryId] if ok { entryIdsMap[s.EntryId] = true } else { if !s.Enabled { err := svc.Enable(s, s.GetCreatedBy()) if err != nil { trace.PrintError(err) continue } } } } // remove non-existent entries for id, ok := range entryIdsMap { if !ok { svc.cron.Remove(id) } } } func (svc *ServiceV2) getEntryIdsMap() (res map[cron.EntryID]bool) { res = map[cron.EntryID]bool{} for _, e := range svc.cron.Entries() { res[e.ID] = false } return res } func (svc *ServiceV2) fetch() (err error) { query := bson.M{ "enabled": true, } svc.schedules, err = svc.modelSvc.GetMany(query, nil) if err != nil { return err } return nil } func (svc *ServiceV2) schedule(id primitive.ObjectID) (fn func()) { return func() { // schedule s, err := svc.modelSvc.GetById(id) if err != nil { trace.PrintError(err) return } // spider spider, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(s.SpiderId) if err != nil { trace.PrintError(err) return } // options opts := &interfaces.SpiderRunOptions{ Mode: s.Mode, NodeIds: s.NodeIds, Cmd: s.Cmd, Param: s.Param, Priority: s.Priority, ScheduleId: s.Id, UserId: s.GetCreatedBy(), } // normalize options if opts.Mode == "" { opts.Mode = spider.Mode } if len(opts.NodeIds) == 0 { opts.NodeIds = spider.NodeIds } if opts.Cmd == "" { opts.Cmd = spider.Cmd } if opts.Param == "" { opts.Param = spider.Param } if opts.Priority == 0 { if spider.Priority > 0 { opts.Priority = spider.Priority } else { opts.Priority = 5 } } // schedule or assign a task in the task queue if _, err := svc.adminSvc.Schedule(s.SpiderId, opts); err != nil { trace.PrintError(err) } } } func NewScheduleServiceV2() (svc2 *ServiceV2, err error) { // service svc := &ServiceV2{ WithConfigPath: config.NewConfigPathService(), loc: time.Local, // TODO: implement delay and skip delay: false, skip: false, updateInterval: 1 * time.Minute, } svc.adminSvc, err = admin.GetSpiderAdminServiceV2() if err != nil { return nil, err } svc.modelSvc = service.NewModelServiceV2[models2.ScheduleV2]() // logger svc.logger = NewLogger() // cron svc.cron = cron.New( cron.WithLogger(svc.logger), cron.WithLocation(svc.loc), cron.WithChain(cron.Recover(svc.logger)), ) // initialize if err := svc.Init(); err != nil { return nil, err } return svc, nil } var svcV2 *ServiceV2 var svcV2Once = new(sync.Once) func GetScheduleServiceV2() (res *ServiceV2, err error) { if svcV2 != nil { return svcV2, nil } svcV2Once.Do(func() { svcV2, err = NewScheduleServiceV2() if err != nil { log.Errorf("failed to get schedule service: %v", err) } }) if err != nil { return nil, err } return svcV2, nil } ================================================ FILE: core/schedule/test/base.go ================================================ package test import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/schedule" "go.uber.org/dig" "testing" ) func init() { var err error T, err = NewTest() if err != nil { panic(err) } } var T *Test type Test struct { // dependencies modelSvc service.ModelService scheduleSvc interfaces.ScheduleService // test data TestSchedule interfaces.Schedule TestSpider interfaces.Spider ScriptName string Script string } func (t *Test) Setup(t2 *testing.T) { t.scheduleSvc.Start() t2.Cleanup(t.Cleanup) } func (t *Test) Cleanup() { t.scheduleSvc.Stop() _ = t.modelSvc.GetBaseService(interfaces.ModelIdTask).Delete(nil) } func NewTest() (t *Test, err error) { // test t = &Test{ TestSpider: &models.Spider{ Name: "test_spider", Cmd: "go run main.go", }, ScriptName: "main.go", Script: `package main import "fmt" func main() { fmt.Println("it works") }`, } // dependency injection c := dig.New() if err := c.Provide(service.GetService); err != nil { return nil, err } if err := c.Provide(schedule.NewScheduleService); err != nil { return nil, err } if err := c.Invoke(func(modelSvc service.ModelService, scheduleSvc interfaces.ScheduleService) { t.modelSvc = modelSvc t.scheduleSvc = scheduleSvc }); err != nil { return nil, err } // add spider to db if err := delegate.NewModelDelegate(t.TestSpider).Add(); err != nil { return nil, err } // test schedule t.TestSchedule = &models.Schedule{ Name: "test_schedule", SpiderId: t.TestSpider.GetId(), Cron: "* * * * *", } if err := delegate.NewModelDelegate(t.TestSchedule).Add(); err != nil { return nil, err } return t, nil } ================================================ FILE: core/schedule/test/schedule_service_test.go ================================================ package test import ( "github.com/stretchr/testify/require" "testing" "time" ) func TestScheduleService_Enable_Disable(t *testing.T) { var err error T.Setup(t) time.Sleep(1 * time.Second) err = T.scheduleSvc.Enable(T.TestSchedule) require.Nil(t, err) time.Sleep(1 * time.Second) require.True(t, T.TestSchedule.GetEnabled()) require.Greater(t, int(T.TestSchedule.GetEntryId()), -1) e := T.scheduleSvc.GetCron().Entry(T.TestSchedule.GetEntryId()) require.Equal(t, T.TestSchedule.GetEntryId(), e.ID) time.Sleep(1 * time.Second) err = T.scheduleSvc.Disable(T.TestSchedule) require.False(t, T.TestSchedule.GetEnabled()) require.Equal(t, 0, len(T.scheduleSvc.GetCron().Entries())) } func TestScheduleService_Run(t *testing.T) { var err error T.Setup(t) time.Sleep(1 * time.Second) err = T.scheduleSvc.Enable(T.TestSchedule) require.Nil(t, err) time.Sleep(1 * time.Minute) tasks, err := T.modelSvc.GetTaskList(nil, nil) require.Nil(t, err) require.Greater(t, len(tasks), 0) for _, task := range tasks { require.False(t, task.ScheduleId.IsZero()) } } ================================================ FILE: core/spider/admin/options.go ================================================ package admin import "github.com/crawlab-team/crawlab/core/interfaces" type Option func(svc interfaces.SpiderAdminService) func WithConfigPath(path string) Option { return func(svc interfaces.SpiderAdminService) { svc.SetConfigPath(path) } } ================================================ FILE: core/spider/admin/service.go ================================================ package admin import ( "context" "github.com/apex/log" config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/crawlab-team/crawlab/vcs" "github.com/google/uuid" "github.com/robfig/cron/v3" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "os" "path" "path/filepath" "sync" "time" ) type Service struct { // dependencies nodeCfgSvc interfaces.NodeConfigService modelSvc service.ModelService schedulerSvc interfaces.TaskSchedulerService cron *cron.Cron syncLock bool // settings cfgPath string } func (svc *Service) GetConfigPath() (path string) { return svc.cfgPath } func (svc *Service) SetConfigPath(path string) { svc.cfgPath = path } func (svc *Service) Start() (err error) { return svc.SyncGit() } func (svc *Service) Schedule(id primitive.ObjectID, opts *interfaces.SpiderRunOptions) (taskIds []primitive.ObjectID, err error) { // spider s, err := svc.modelSvc.GetSpiderById(id) if err != nil { return nil, err } // assign tasks return svc.scheduleTasks(s, opts) } func (svc *Service) Clone(id primitive.ObjectID, opts *interfaces.SpiderCloneOptions) (err error) { // TODO: implement return nil } func (svc *Service) Delete(id primitive.ObjectID) (err error) { panic("implement me") } func (svc *Service) SyncGit() (err error) { if _, err = svc.cron.AddFunc("* * * * *", svc.syncGit); err != nil { return trace.TraceError(err) } svc.cron.Start() return nil } func (svc *Service) SyncGitOne(g interfaces.Git) (err error) { svc.syncGitOne(g) return nil } func (svc *Service) Export(id primitive.ObjectID) (filePath string, err error) { // spider fs workspacePath := viper.GetString("workspace") spiderFolderPath := filepath.Join(workspacePath, id.Hex()) // zip files in workspace dirPath := spiderFolderPath zipFilePath := path.Join(os.TempDir(), uuid.New().String()+".zip") if err := utils.ZipDirectory(dirPath, zipFilePath); err != nil { return "", trace.TraceError(err) } return zipFilePath, nil } func (svc *Service) scheduleTasks(s *models.Spider, opts *interfaces.SpiderRunOptions) (taskIds []primitive.ObjectID, err error) { // main task mainTask := &models.Task{ SpiderId: s.Id, Mode: opts.Mode, NodeIds: opts.NodeIds, Cmd: opts.Cmd, Param: opts.Param, ScheduleId: opts.ScheduleId, Priority: opts.Priority, UserId: opts.UserId, CreateTs: time.Now(), } // normalize if mainTask.Mode == "" { mainTask.Mode = s.Mode } if mainTask.NodeIds == nil { mainTask.NodeIds = s.NodeIds } if mainTask.Cmd == "" { mainTask.Cmd = s.Cmd } if mainTask.Param == "" { mainTask.Param = s.Param } if mainTask.Priority == 0 { mainTask.Priority = s.Priority } if svc.isMultiTask(opts) { // multi tasks nodeIds, err := svc.getNodeIds(opts) if err != nil { return nil, err } for _, nodeId := range nodeIds { t := &models.Task{ SpiderId: s.Id, Mode: opts.Mode, Cmd: opts.Cmd, Param: opts.Param, NodeId: nodeId, ScheduleId: opts.ScheduleId, Priority: opts.Priority, UserId: opts.UserId, CreateTs: time.Now(), } t2, err := svc.schedulerSvc.Enqueue(t) if err != nil { return nil, err } taskIds = append(taskIds, t2.GetId()) } } else { // single task nodeIds, err := svc.getNodeIds(opts) if err != nil { return nil, err } if len(nodeIds) > 0 { mainTask.NodeId = nodeIds[0] } t2, err := svc.schedulerSvc.Enqueue(mainTask) if err != nil { return nil, err } taskIds = append(taskIds, t2.GetId()) } return taskIds, nil } func (svc *Service) getNodeIds(opts *interfaces.SpiderRunOptions) (nodeIds []primitive.ObjectID, err error) { if opts.Mode == constants.RunTypeAllNodes { query := bson.M{ "active": true, "enabled": true, "status": constants.NodeStatusOnline, } nodes, err := svc.modelSvc.GetNodeList(query, nil) if err != nil { return nil, err } for _, node := range nodes { nodeIds = append(nodeIds, node.GetId()) } } else if opts.Mode == constants.RunTypeSelectedNodes { nodeIds = opts.NodeIds } return nodeIds, nil } func (svc *Service) isMultiTask(opts *interfaces.SpiderRunOptions) (res bool) { if opts.Mode == constants.RunTypeAllNodes { query := bson.M{ "active": true, "enabled": true, "status": constants.NodeStatusOnline, } nodes, err := svc.modelSvc.GetNodeList(query, nil) if err != nil { trace.PrintError(err) return false } return len(nodes) > 1 } else if opts.Mode == constants.RunTypeRandom { return false } else if opts.Mode == constants.RunTypeSelectedNodes { return len(opts.NodeIds) > 1 } else { return false } } func (svc *Service) syncGit() { if svc.syncLock { log.Infof("[SpiderAdminService] sync git is locked, skip") return } log.Infof("[SpiderAdminService] start to sync git") svc.syncLock = true defer func() { svc.syncLock = false }() // spiders spiders, err := svc.modelSvc.GetSpiderList(nil, nil) if err != nil { trace.PrintError(err) return } // spider ids var spiderIds []primitive.ObjectID for _, s := range spiders { spiderIds = append(spiderIds, s.Id) } if len(spiderIds) > 0 { // gits gits, err := svc.modelSvc.GetGitList(bson.M{ "_id": bson.M{ "$in": spiderIds, }, "auto_pull": true, }, nil) if err != nil { trace.PrintError(err) return } wg := sync.WaitGroup{} wg.Add(len(gits)) for _, g := range gits { go func(g models.Git) { svc.syncGitOne(&g) wg.Done() }(g) } wg.Wait() } log.Infof("[SpiderAdminService] finished sync git") } func (svc *Service) syncGitOne(g interfaces.Git) { log.Infof("[SpiderAdminService] sync git %s", g.GetId()) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() // git client workspacePath := viper.GetString("workspace") gitClient, err := vcs.NewGitClient(vcs.WithPath(filepath.Join(workspacePath, g.GetId().Hex()))) if err != nil { return } // set auth utils.InitGitClientAuth(g, gitClient) // check if remote has changes ok, err := gitClient.IsRemoteChanged() if err != nil { trace.PrintError(err) return } if !ok { // no change return } // pull and sync to workspace if err := gitClient.Reset(); err != nil { trace.PrintError(err) return } if err := gitClient.Pull(); err != nil { trace.PrintError(err) return } // wait for context to end <-ctx.Done() } func NewSpiderAdminService(opts ...Option) (svc2 interfaces.SpiderAdminService, err error) { svc := &Service{ cfgPath: config2.GetConfigPath(), } // apply options for _, opt := range opts { opt(svc) } // dependency injection if err := container.GetContainer().Invoke(func(nodeCfgSvc interfaces.NodeConfigService, modelSvc service.ModelService, schedulerSvc interfaces.TaskSchedulerService) { svc.nodeCfgSvc = nodeCfgSvc svc.modelSvc = modelSvc svc.schedulerSvc = schedulerSvc }); err != nil { return nil, trace.TraceError(err) } // cron svc.cron = cron.New() // validate node type if !svc.nodeCfgSvc.IsMaster() { return nil, trace.TraceError(errors.ErrorSpiderForbidden) } return svc, nil } var _service interfaces.SpiderAdminService func GetSpiderAdminService() (svc2 interfaces.SpiderAdminService, err error) { if _service != nil { return _service, nil } _service, err = NewSpiderAdminService() if err != nil { return nil, err } return _service, nil } ================================================ FILE: core/spider/admin/service_v2.go ================================================ package admin import ( log2 "github.com/apex/log" config2 "github.com/crawlab-team/crawlab/core/config" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/task/scheduler" "github.com/crawlab-team/crawlab/trace" "github.com/robfig/cron/v3" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "sync" ) type ServiceV2 struct { // dependencies nodeCfgSvc interfaces.NodeConfigService schedulerSvc *scheduler.ServiceV2 cron *cron.Cron syncLock bool // settings cfgPath string } func (svc *ServiceV2) Schedule(id primitive.ObjectID, opts *interfaces.SpiderRunOptions) (taskIds []primitive.ObjectID, err error) { // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(id) if err != nil { return nil, err } // assign tasks return svc.scheduleTasks(s, opts) } func (svc *ServiceV2) scheduleTasks(s *models2.SpiderV2, opts *interfaces.SpiderRunOptions) (taskIds []primitive.ObjectID, err error) { // main task t := &models2.TaskV2{ SpiderId: s.Id, Mode: opts.Mode, NodeIds: opts.NodeIds, Cmd: opts.Cmd, Param: opts.Param, ScheduleId: opts.ScheduleId, Priority: opts.Priority, } t.SetId(primitive.NewObjectID()) // normalize if t.Mode == "" { t.Mode = s.Mode } if t.NodeIds == nil { t.NodeIds = s.NodeIds } if t.Cmd == "" { t.Cmd = s.Cmd } if t.Param == "" { t.Param = s.Param } if t.Priority == 0 { t.Priority = s.Priority } nodeIds, err := svc.getNodeIds(opts) if err != nil { return nil, err } if len(nodeIds) > 0 { t.NodeId = nodeIds[0] } t2, err := svc.schedulerSvc.Enqueue(t, opts.UserId) if err != nil { return nil, err } taskIds = append(taskIds, t2.Id) return taskIds, nil } func (svc *ServiceV2) getNodeIds(opts *interfaces.SpiderRunOptions) (nodeIds []primitive.ObjectID, err error) { if opts.Mode == constants.RunTypeAllNodes { query := bson.M{ "active": true, "enabled": true, "status": constants.NodeStatusOnline, } nodes, err := service.NewModelServiceV2[models2.NodeV2]().GetMany(query, nil) if err != nil { return nil, err } for _, node := range nodes { nodeIds = append(nodeIds, node.Id) } } else if opts.Mode == constants.RunTypeSelectedNodes { nodeIds = opts.NodeIds } return nodeIds, nil } func (svc *ServiceV2) isMultiTask(opts *interfaces.SpiderRunOptions) (res bool) { if opts.Mode == constants.RunTypeAllNodes { query := bson.M{ "active": true, "enabled": true, "status": constants.NodeStatusOnline, } nodes, err := service.NewModelServiceV2[models2.NodeV2]().GetMany(query, nil) if err != nil { trace.PrintError(err) return false } return len(nodes) > 1 } else if opts.Mode == constants.RunTypeRandom { return false } else if opts.Mode == constants.RunTypeSelectedNodes { return len(opts.NodeIds) > 1 } else { return false } } func newSpiderAdminServiceV2() (svc2 *ServiceV2, err error) { svc := &ServiceV2{ nodeCfgSvc: config.GetNodeConfigService(), cfgPath: config2.GetConfigPath(), } svc.schedulerSvc, err = scheduler.GetTaskSchedulerServiceV2() if err != nil { return nil, err } // cron svc.cron = cron.New() // validate node type if !svc.nodeCfgSvc.IsMaster() { return nil, trace.TraceError(errors.ErrorSpiderForbidden) } return svc, nil } var svcV2 *ServiceV2 var svcV2Once = new(sync.Once) func GetSpiderAdminServiceV2() (svc2 *ServiceV2, err error) { if svcV2 != nil { return svcV2, nil } svcV2Once.Do(func() { svcV2, err = newSpiderAdminServiceV2() if err != nil { log2.Errorf("[GetSpiderAdminServiceV2] error: %v", err) } }) if err != nil { return nil, err } return svcV2, nil } ================================================ FILE: core/stats/options.go ================================================ package stats import "github.com/crawlab-team/crawlab/core/interfaces" type Option func(svc interfaces.StatsService) ================================================ FILE: core/stats/service.go ================================================ package stats import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" mongo2 "go.mongodb.org/mongo-driver/mongo" ) type Service struct { } func (svc *Service) GetOverviewStats(query bson.M) (data interface{}, err error) { stats := bson.M{} // nodes stats["nodes"], err = mongo.GetMongoCol(interfaces.ModelColNameNode).Count(bson.M{"active": true}) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["nodes"] = 0 } // projects stats["projects"], err = mongo.GetMongoCol(interfaces.ModelColNameProject).Count(nil) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["projects"] = 0 } // spiders stats["spiders"], err = mongo.GetMongoCol(interfaces.ModelColNameSpider).Count(nil) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["spiders"] = 0 } // schedules stats["schedules"], err = mongo.GetMongoCol(interfaces.ModelColNameSchedule).Count(nil) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["schedules"] = 0 } // tasks stats["tasks"], err = mongo.GetMongoCol(interfaces.ModelColNameTask).Count(nil) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["tasks"] = 0 } // error tasks stats["error_tasks"], err = mongo.GetMongoCol(interfaces.ModelColNameTask).Count(bson.M{"status": constants.TaskStatusError}) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["error_tasks"] = 0 } // results stats["results"], err = svc.getOverviewResults(query) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["results"] = 0 } // users stats["users"], err = mongo.GetMongoCol(interfaces.ModelColNameUser).Count(nil) if err != nil { if err.Error() != mongo2.ErrNoDocuments.Error() { return nil, err } stats["users"] = 0 } return stats, nil } func (svc *Service) GetDailyStats(query bson.M) (data interface{}, err error) { tasksStats, err := svc.getDailyTasksStats(query) if err != nil { return nil, err } return tasksStats, nil } func (svc *Service) GetTaskStats(query bson.M) (data interface{}, err error) { stats := bson.M{} // by status stats["by_status"], err = svc.getTaskStatsByStatus(query) if err != nil { return nil, err } // by node stats["by_node"], err = svc.getTaskStatsByNode(query) if err != nil { return nil, err } // by spider stats["by_spider"], err = svc.getTaskStatsBySpider(query) if err != nil { return nil, err } return stats, nil } func (svc *Service) getDailyTasksStats(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{ "$match", query, }}, {{ "$addFields", bson.M{ "date": bson.M{ "$dateToString": bson.M{ "date": bson.M{"$toDate": "$_id"}, "format": "%Y-%m-%d", "timezone": "Asia/Shanghai", // TODO: parameterization }, }, }, }}, {{ "$group", bson.M{ "_id": "$date", "tasks": bson.M{"$sum": 1}, "results": bson.M{"$sum": "$result_count"}, }, }}, {{ "$sort", bson.D{{"_id", 1}}, }}, } var results []entity.StatsDailyItem if err := mongo.GetMongoCol(interfaces.ModelColNameTaskStat).Aggregate(pipeline, nil).All(&results); err != nil { return nil, err } return results, nil } func (svc *Service) getOverviewResults(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{"$match", query}}, {{ "$group", bson.M{ "_id": nil, "results": bson.M{"$sum": "$result_count"}, }, }}, } var res bson.M if err := mongo.GetMongoCol(interfaces.ModelColNameTaskStat).Aggregate(pipeline, nil).One(&res); err != nil { return nil, err } return res["results"], nil } func (svc *Service) getTaskStatsByStatus(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{"$match", query}}, {{ "$group", bson.M{ "_id": "$status", "tasks": bson.M{"$sum": 1}, }, }}, {{ "$project", bson.M{ "status": "$_id", "tasks": "$tasks", }, }}, } var results []bson.M if err := mongo.GetMongoCol(interfaces.ModelColNameTask).Aggregate(pipeline, nil).All(&results); err != nil { return nil, err } return results, nil } func (svc *Service) getTaskStatsByNode(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{"$match", query}}, {{ "$group", bson.M{ "_id": "$node_id", "tasks": bson.M{"$sum": 1}, }, }}, {{ "$lookup", bson.M{ "from": interfaces.ModelColNameNode, "localField": "_id", "foreignField": "_id", "as": "_n", }, }}, {{ "$project", bson.M{ "node_id": "$node_id", "node": bson.M{"$arrayElemAt": bson.A{"$_n", 0}}, "node_name": bson.M{"$arrayElemAt": bson.A{"$_n.name", 0}}, "tasks": "$tasks", }, }}, } var results []bson.M if err := mongo.GetMongoCol(interfaces.ModelColNameTask).Aggregate(pipeline, nil).All(&results); err != nil { return nil, err } return results, nil } func (svc *Service) getTaskStatsBySpider(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{"$match", query}}, {{ "$group", bson.M{ "_id": "$spider_id", "tasks": bson.M{"$sum": 1}, }, }}, {{ "$lookup", bson.M{ "from": interfaces.ModelColNameSpider, "localField": "_id", "foreignField": "_id", "as": "_s", }, }}, {{ "$project", bson.M{ "spider_id": "$spider_id", "spider": bson.M{"$arrayElemAt": bson.A{"$_s", 0}}, "spider_name": bson.M{"$arrayElemAt": bson.A{"$_s.name", 0}}, "tasks": "$tasks", }, }}, {{"$limit", 10}}, } var results []bson.M if err := mongo.GetMongoCol(interfaces.ModelColNameTask).Aggregate(pipeline, nil).All(&results); err != nil { return nil, err } return results, nil } func (svc *Service) getTaskStatsHistogram(query bson.M) (data interface{}, err error) { pipeline := mongo2.Pipeline{ {{"$match", query}}, {{ "$lookup", bson.M{ "from": interfaces.ModelColNameTaskStat, "localField": "_id", "foreignField": "_id", "as": "_ts", }, }}, {{ "$facet", bson.M{ "total_duration": bson.A{ bson.M{ "$bucketAuto": bson.M{ "groupBy": "$_ts.td", "buckets": 10, "granularity": "1-2-5", }, }, }, }, }}, } var res bson.M if err := mongo.GetMongoCol(interfaces.ModelColNameTask).Aggregate(pipeline, nil).One(&res); err != nil { return nil, err } return res, nil } var svc interfaces.StatsService func GetStatsService() interfaces.StatsService { if svc != nil { return svc } // service svc = &Service{} return svc } ================================================ FILE: core/sys_exec/sys_exec.go ================================================ package sys_exec import ( "bufio" "github.com/crawlab-team/crawlab/trace" "github.com/shirou/gopsutil/process" "os/exec" "time" ) type KillProcessOptions struct { Timeout time.Duration Force bool } func KillProcess(cmd *exec.Cmd, opts *KillProcessOptions) error { // process p, err := process.NewProcess(int32(cmd.Process.Pid)) if err != nil { return err } // kill function killFunc := func(p *process.Process) error { return killProcessRecursive(p, opts.Force) } if opts.Timeout != 0 { // with timeout return killProcessWithTimeout(p, opts.Timeout, killFunc) } else { // without timeout return killFunc(p) } } func killProcessWithTimeout(p *process.Process, timeout time.Duration, killFunc func(*process.Process) error) error { go func() { if err := killFunc(p); err != nil { trace.PrintError(err) } }() for i := 0; i < int(timeout.Seconds()); i++ { ok, err := process.PidExists(p.Pid) if err == nil && !ok { return nil } time.Sleep(1 * time.Second) } return killProcess(p, true) } func killProcessRecursive(p *process.Process, force bool) (err error) { // children processes cps, err := p.Children() if err != nil { return killProcess(p, force) } // iterate children processes for _, cp := range cps { if err := killProcessRecursive(cp, force); err != nil { return err } } return nil } func killProcess(p *process.Process, force bool) (err error) { if force { err = p.Kill() } else { err = p.Terminate() } if err != nil { return trace.TraceError(err) } return nil } func ConfigureCmdLogging(cmd *exec.Cmd, fn func(scanner *bufio.Scanner)) { stdout, _ := (*cmd).StdoutPipe() stderr, _ := (*cmd).StderrPipe() scannerStdout := bufio.NewScanner(stdout) scannerStderr := bufio.NewScanner(stderr) go fn(scannerStdout) go fn(scannerStderr) } ================================================ FILE: core/sys_exec/sys_exec_darwin.go ================================================ //go:build darwin // +build darwin package sys_exec import ( "errors" "os/exec" "strings" "syscall" ) func BuildCmd(cmdStr string) (cmd *exec.Cmd, err error) { if cmdStr == "" { return nil, errors.New("command string is empty") } args := strings.Split(cmdStr, " ") return exec.Command(args[0], args[1:]...), nil } func SetPgid(cmd *exec.Cmd) { if cmd == nil { return } if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} } else { cmd.SysProcAttr.Setpgid = true } } ================================================ FILE: core/sys_exec/sys_exec_linux.go ================================================ //go:build linux // +build linux package sys_exec import ( "errors" "os/exec" "strings" "syscall" ) func BuildCmd(cmdStr string) (cmd *exec.Cmd, err error) { if cmdStr == "" { return nil, errors.New("command string is empty") } args := strings.Split(cmdStr, " ") return exec.Command(args[0], args[1:]...), nil } func SetPgid(cmd *exec.Cmd) { if cmd == nil { return } if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} } else { cmd.SysProcAttr.Setpgid = true } } ================================================ FILE: core/sys_exec/sys_exec_windows.go ================================================ //go:build windows // +build windows package sys_exec import ( "errors" "os/exec" "strings" ) func BuildCmd(cmdStr string) (cmd *exec.Cmd, err error) { if cmdStr == "" { return nil, errors.New("command string is empty") } args := strings.Split(cmdStr, " ") return exec.Command(args[0], args[1:]...), nil } ================================================ FILE: core/system/service.go ================================================ package system import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" mongo2 "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type Service struct { col *mongo2.Col modelSvc service.ModelService } func (svc *Service) Init() (err error) { // initialize data if err := svc.initData(); err != nil { return err } return nil } func (svc *Service) initData() (err error) { total, err := svc.col.Count(bson.M{ "key": "customize", }) if err != nil { return err } if total > 0 { return nil } // data to initialize settings := []models.Setting{ { Id: primitive.NewObjectID(), Key: "customize", Value: bson.M{ "show_custom_title": false, "custom_title": "", "show_custom_logo": false, "custom_logo": "", "hide_platform_version": false, }, }, } var data []interface{} for _, s := range settings { data = append(data, s) } _, err = svc.col.InsertMany(data) if err != nil { return err } return nil } func NewService() *Service { // service svc := &Service{ col: mongo2.GetMongoCol(interfaces.ModelColNameSetting), } // model service modelSvc, err := service.GetService() if err != nil { panic(err) } svc.modelSvc = modelSvc if err := svc.Init(); err != nil { panic(err) } return svc } var _service *Service func GetService() *Service { if _service == nil { _service = NewService() } return _service } ================================================ FILE: core/system/service_v2.go ================================================ package system import ( "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "go.mongodb.org/mongo-driver/bson" "sync" ) type ServiceV2 struct { } func (svc *ServiceV2) Init() (err error) { // initialize data if err := svc.initData(); err != nil { return err } return nil } func (svc *ServiceV2) initData() (err error) { total, err := service.NewModelServiceV2[models.SettingV2]().Count(bson.M{ "key": "site_title", }) if err != nil { return err } if total > 0 { return nil } // data to initialize settings := []models.SettingV2{ { Key: "site_title", Value: bson.M{ "customize_site_title": false, "site_title": "", }, }, } _, err = service.NewModelServiceV2[models.SettingV2]().InsertMany(settings) if err != nil { return err } return nil } func newSystemServiceV2() *ServiceV2 { // service svc := &ServiceV2{} if err := svc.Init(); err != nil { panic(err) } return svc } var _serviceV2 *ServiceV2 var _serviceV2Once = new(sync.Once) func GetSystemServiceV2() *ServiceV2 { if _serviceV2 == nil { _serviceV2 = newSystemServiceV2() } _serviceV2Once.Do(func() { _serviceV2 = newSystemServiceV2() }) return _serviceV2 } ================================================ FILE: core/task/handler/options.go ================================================ package handler import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Option func(svc interfaces.TaskHandlerService) func WithConfigPath(path string) Option { return func(svc interfaces.TaskHandlerService) { svc.SetConfigPath(path) } } func WithExitWatchDuration(duration time.Duration) Option { return func(svc interfaces.TaskHandlerService) { svc.SetExitWatchDuration(duration) } } func WithReportInterval(interval time.Duration) Option { return func(svc interfaces.TaskHandlerService) { svc.SetReportInterval(interval) } } func WithCancelTimeout(timeout time.Duration) Option { return func(svc interfaces.TaskHandlerService) { svc.SetCancelTimeout(timeout) } } type RunnerOption func(r interfaces.TaskRunner) func WithSubscribeTimeout(timeout time.Duration) RunnerOption { return func(r interfaces.TaskRunner) { r.SetSubscribeTimeout(timeout) } } ================================================ FILE: core/task/handler/runner_test.go ================================================ package handler import ( "github.com/crawlab-team/crawlab/core/models/models" "github.com/google/uuid" "github.com/spf13/viper" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) type MockRunner struct { mock.Mock Runner } func (m *MockRunner) downloadFile(url string, filePath string) error { args := m.Called(url, filePath) return args.Error(0) } func newMockRunner() *MockRunner { r := &MockRunner{} r.s = &models.Spider{} return r } func TestSyncFiles_SuccessWithDummyFiles(t *testing.T) { // Create a test server that responds with a list of files ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(r.URL.Path, "/scan") { w.Write([]byte(`{"file1.txt":{"path": "file1.txt", "hash": "hash1"}, "file2.txt":{"path": "file2.txt", "hash": "hash2"}}`)) return } if strings.HasSuffix(r.URL.Path, "/download") { w.Write([]byte("file content")) return } })) defer ts.Close() // Create a mock runner r := newMockRunner() r.On("downloadFile", mock.Anything, mock.Anything).Return(nil) // Set the master URL to the test server URL viper.Set("api.endpoint", ts.URL) localPath := filepath.Join(os.TempDir(), uuid.New().String()) os.MkdirAll(filepath.Join(localPath, r.s.GetId().Hex()), os.ModePerm) defer os.RemoveAll(localPath) viper.Set("workspace", localPath) // Call the method under test err := r.syncFiles() assert.NoError(t, err) // Assert that the files were downloaded assert.FileExists(t, filepath.Join(localPath, r.s.GetId().Hex(), "file1.txt")) assert.FileExists(t, filepath.Join(localPath, r.s.GetId().Hex(), "file2.txt")) } func TestSyncFiles_DeletesFilesNotOnMaster(t *testing.T) { // Create a test server that responds with an empty list of files ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(r.URL.Path, "/scan") { w.Write([]byte(`{}`)) return } })) defer ts.Close() // Create a mock runner r := newMockRunner() r.On("downloadFile", mock.Anything, mock.Anything).Return(nil) // Set the master URL to the test server URL viper.Set("api.endpoint", ts.URL) localPath := filepath.Join(os.TempDir(), uuid.New().String()) os.MkdirAll(filepath.Join(localPath, r.s.GetId().Hex()), os.ModePerm) defer os.RemoveAll(localPath) viper.Set("workspace", localPath) // Create a dummy file that should be deleted dummyFilePath := filepath.Join(localPath, r.s.GetId().Hex(), "dummy.txt") dummyFile, _ := os.Create(dummyFilePath) dummyFile.Close() // Call the method under test err := r.syncFiles() assert.NoError(t, err) // Assert that the dummy file was deleted assert.NoFileExists(t, dummyFilePath) } ================================================ FILE: core/task/handler/runner_v2.go ================================================ package handler import ( "bufio" "context" "encoding/json" "errors" "fmt" "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" fs2 "github.com/crawlab-team/crawlab/core/fs" client2 "github.com/crawlab-team/crawlab/core/grpc/client" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/client" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" service2 "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/sys_exec" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "github.com/shirou/gopsutil/process" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "io" "net/http" "os" "os/exec" "path/filepath" "strings" "sync" "time" ) type RunnerV2 struct { // dependencies svc *ServiceV2 // task handler service fsSvc interfaces.FsServiceV2 // task fs service // settings subscribeTimeout time.Duration bufferSize int // internals cmd *exec.Cmd // process command instance pid int // process id tid primitive.ObjectID // task id t *models2.TaskV2 // task model.Task s *models2.SpiderV2 // spider model.Spider ch chan constants.TaskSignal // channel to communicate between Service and RunnerV2 err error // standard process error envs []models.Env // environment variables cwd string // working directory c *client2.GrpcClientV2 // grpc client sub grpc.TaskService_SubscribeClient // grpc task service stream client // log internals scannerStdout *bufio.Reader scannerStderr *bufio.Reader logBatchSize int } func (r *RunnerV2) Init() (err error) { // update task if err := r.updateTask("", nil); err != nil { return err } // start grpc client if !r.c.IsStarted() { err := r.c.Start() if err != nil { return err } } // grpc task service stream client if err := r.initSub(); err != nil { return err } return nil } func (r *RunnerV2) Run() (err error) { // log task started log.Infof("task[%s] started", r.tid.Hex()) // configure working directory r.configureCwd() // sync files worker nodes if !utils.IsMaster() { if err := r.syncFiles(); err != nil { return r.updateTask(constants.TaskStatusError, err) } } // configure cmd err = r.configureCmd() if err != nil { return r.updateTask(constants.TaskStatusError, err) } // configure environment variables r.configureEnv() // configure logging r.configureLogging() // start process if err := r.cmd.Start(); err != nil { return r.updateTask(constants.TaskStatusError, err) } // start logging go r.startLogging() // process id if r.cmd.Process == nil { return r.updateTask(constants.TaskStatusError, constants.ErrNotExists) } r.pid = r.cmd.Process.Pid r.t.Pid = r.pid // update task status (processing) if err := r.updateTask(constants.TaskStatusRunning, nil); err != nil { return err } // wait for process to finish go r.wait() // start health check go r.startHealthCheck() // declare task status status := "" // wait for signal signal := <-r.ch switch signal { case constants.TaskSignalFinish: err = nil status = constants.TaskStatusFinished case constants.TaskSignalCancel: err = constants.ErrTaskCancelled status = constants.TaskStatusCancelled case constants.TaskSignalError: err = r.err status = constants.TaskStatusError case constants.TaskSignalLost: err = constants.ErrTaskLost status = constants.TaskStatusError default: err = constants.ErrInvalidSignal status = constants.TaskStatusError } // update task status if err := r.updateTask(status, err); err != nil { return err } return err } func (r *RunnerV2) Cancel() (err error) { // kill process opts := &sys_exec.KillProcessOptions{ Timeout: r.svc.GetCancelTimeout(), Force: true, } if err := sys_exec.KillProcess(r.cmd, opts); err != nil { return err } // make sure the process does not exist op := func() error { if exists, _ := process.PidExists(int32(r.pid)); exists { return errors.New(fmt.Sprintf("task process %d still exists", r.pid)) } return nil } ctx, cancel := context.WithTimeout(context.Background(), r.svc.GetExitWatchDuration()) defer cancel() b := backoff.WithContext(backoff.NewConstantBackOff(1*time.Second), ctx) if err := backoff.Retry(op, b); err != nil { log.Errorf("Error canceling task %s: %v", r.tid, err) return trace.TraceError(err) } return nil } // CleanUp clean up task runner func (r *RunnerV2) CleanUp() (err error) { return nil } func (r *RunnerV2) SetSubscribeTimeout(timeout time.Duration) { r.subscribeTimeout = timeout } func (r *RunnerV2) GetTaskId() (id primitive.ObjectID) { return r.tid } func (r *RunnerV2) configureCmd() (err error) { var cmdStr string // customized spider if r.t.Cmd == "" { cmdStr = r.s.Cmd } else { cmdStr = r.t.Cmd } // parameters if r.t.Param != "" { cmdStr += " " + r.t.Param } else if r.s.Param != "" { cmdStr += " " + r.s.Param } // get cmd instance r.cmd, err = sys_exec.BuildCmd(cmdStr) if err != nil { log.Errorf("Error building command: %v", err) trace.PrintError(err) return err } // set working directory r.cmd.Dir = r.cwd return nil } func (r *RunnerV2) configureLogging() { // set stdout reader stdout, _ := r.cmd.StdoutPipe() r.scannerStdout = bufio.NewReaderSize(stdout, r.bufferSize) // set stderr reader stderr, _ := r.cmd.StderrPipe() r.scannerStderr = bufio.NewReaderSize(stderr, r.bufferSize) } func (r *RunnerV2) startLogging() { // start reading stdout go r.startLoggingReaderStdout() // start reading stderr go r.startLoggingReaderStderr() } func (r *RunnerV2) startLoggingReaderStdout() { for { line, err := r.scannerStdout.ReadString(byte('\n')) if err != nil { break } line = strings.TrimSuffix(line, "\n") r.writeLogLines([]string{line}) } } func (r *RunnerV2) startLoggingReaderStderr() { for { line, err := r.scannerStderr.ReadString(byte('\n')) if err != nil { break } line = strings.TrimSuffix(line, "\n") r.writeLogLines([]string{line}) } } func (r *RunnerV2) startHealthCheck() { if r.cmd.ProcessState == nil || r.cmd.ProcessState.Exited() { return } for { exists, _ := process.PidExists(int32(r.pid)) if !exists { // process lost r.ch <- constants.TaskSignalLost return } time.Sleep(1 * time.Second) } } func (r *RunnerV2) configureEnv() { // 默认把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 envs r.cmd.Env = append(os.Environ(), "CRAWLAB_TASK_ID="+r.tid.Hex()) if viper.GetString("grpc.address") != "" { r.cmd.Env = append(r.cmd.Env, "CRAWLAB_GRPC_ADDRESS="+viper.GetString("grpc.address")) } if viper.GetString("grpc.authKey") != "" { r.cmd.Env = append(r.cmd.Env, "CRAWLAB_GRPC_AUTH_KEY="+viper.GetString("grpc.authKey")) } else { r.cmd.Env = append(r.cmd.Env, "CRAWLAB_GRPC_AUTH_KEY="+constants.DefaultGrpcAuthKey) } // global environment variables envs, err := client.NewModelServiceV2[models2.EnvironmentV2]().GetMany(nil, nil) if err != nil { trace.PrintError(err) return } for _, env := range envs { r.cmd.Env = append(r.cmd.Env, env.Key+"="+env.Value) } } func (r *RunnerV2) syncFiles() (err error) { var id string var workingDir string if r.s.GitId.IsZero() { id = r.s.Id.Hex() workingDir = "" } else { id = r.s.GitId.Hex() workingDir = r.s.GitRootPath } masterURL := fmt.Sprintf("%s/sync/%s", viper.GetString("api.endpoint"), id) // get file list from master resp, err := http.Get(masterURL + "/scan?path=" + workingDir) if err != nil { log.Errorf("Error getting file list from master: %v", err) return trace.TraceError(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Errorf("Error reading response body: %v", err) return trace.TraceError(err) } var masterFiles map[string]entity.FsFileInfo err = json.Unmarshal(body, &masterFiles) if err != nil { log.Errorf("Error unmarshaling JSON: %v", err) return trace.TraceError(err) } // create a map for master files masterFilesMap := make(map[string]entity.FsFileInfo) for _, file := range masterFiles { masterFilesMap[file.Path] = file } // create working directory if not exists if _, err := os.Stat(r.cwd); os.IsNotExist(err) { if err := os.MkdirAll(r.cwd, os.ModePerm); err != nil { log.Errorf("Error creating worker directory: %v", err) return trace.TraceError(err) } } // get file list from worker workerFiles, err := utils.ScanDirectory(r.cwd) if err != nil { log.Errorf("Error scanning worker directory: %v", err) return trace.TraceError(err) } // delete files that are deleted on master node for path, workerFile := range workerFiles { if _, exists := masterFilesMap[path]; !exists { log.Infof("Deleting file: %s", path) err := os.Remove(workerFile.FullPath) if err != nil { log.Errorf("Error deleting file: %v", err) } } } // set up wait group and error channel var wg sync.WaitGroup pool := make(chan struct{}, 10) // download files that are new or modified on master node for path, masterFile := range masterFilesMap { workerFile, exists := workerFiles[path] if !exists || masterFile.Hash != workerFile.Hash { wg.Add(1) // acquire token pool <- struct{}{} // start goroutine to synchronize file or directory go func(path string, masterFile *entity.FsFileInfo) { defer wg.Done() if masterFile.IsDir { log.Infof("Directory needs to be synchronized: %s", path) _err := os.MkdirAll(filepath.Join(r.cwd, path), masterFile.Mode) if _err != nil { log.Errorf("Error creating directory: %v", _err) err = errors.Join(err, _err) } } else { log.Infof("File needs to be synchronized: %s", path) _err := r.downloadFile(masterURL+"/download?path="+filepath.Join(workingDir, path), filepath.Join(r.cwd, path), masterFile) if _err != nil { log.Errorf("Error downloading file: %v", _err) err = errors.Join(err, _err) } } // release token <-pool }(path, &masterFile) } } // wait for all files and directories to be synchronized wg.Wait() return err } func (r *RunnerV2) downloadFile(url string, filePath string, fileInfo *entity.FsFileInfo) error { // get file response resp, err := http.Get(url) if err != nil { log.Errorf("Error getting file response: %v", err) return err } if resp.StatusCode != http.StatusOK { log.Errorf("Error downloading file: %s", resp.Status) return errors.New(resp.Status) } defer resp.Body.Close() // create directory if not exists dirPath := filepath.Dir(filePath) utils.Exists(dirPath) err = os.MkdirAll(dirPath, os.ModePerm) if err != nil { log.Errorf("Error creating directory: %v", err) return err } // create local file out, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileInfo.Mode) if err != nil { log.Errorf("Error creating file: %v", err) return err } defer out.Close() // copy file content to local file _, err = io.Copy(out, resp.Body) if err != nil { log.Errorf("Error copying file: %v", err) return err } return nil } // wait for process to finish and send task signal (constants.TaskSignal) // to task runner's channel (RunnerV2.ch) according to exit code func (r *RunnerV2) wait() { // wait for process to finish if err := r.cmd.Wait(); err != nil { var exitError *exec.ExitError ok := errors.As(err, &exitError) if !ok { r.ch <- constants.TaskSignalError return } exitCode := exitError.ExitCode() if exitCode == -1 { // cancel error r.ch <- constants.TaskSignalCancel return } // standard error r.err = err r.ch <- constants.TaskSignalError return } // success r.ch <- constants.TaskSignalFinish } // updateTask update and get updated info of task (RunnerV2.t) func (r *RunnerV2) updateTask(status string, e error) (err error) { if r.t != nil && status != "" { // update task status r.t.Status = status if e != nil { r.t.Error = e.Error() } if r.svc.GetNodeConfigService().IsMaster() { err = service2.NewModelServiceV2[models2.TaskV2]().ReplaceById(r.t.Id, *r.t) if err != nil { return err } } else { err = client.NewModelServiceV2[models2.TaskV2]().ReplaceById(r.t.Id, *r.t) if err != nil { return err } } // update stats r._updateTaskStat(status) r._updateSpiderStat(status) // send notification go r.sendNotification() } // get task r.t, err = r.svc.GetTaskById(r.tid) if err != nil { return err } return nil } func (r *RunnerV2) initSub() (err error) { r.sub, err = r.c.TaskClient.Subscribe(context.Background()) if err != nil { return trace.TraceError(err) } return nil } func (r *RunnerV2) writeLogLines(lines []string) { data, err := json.Marshal(&entity.StreamMessageTaskData{ TaskId: r.tid, Logs: lines, }) if err != nil { trace.PrintError(err) return } msg := &grpc.StreamMessage{ Code: grpc.StreamMessageCode_INSERT_LOGS, Data: data, } if err := r.sub.Send(msg); err != nil { trace.PrintError(err) return } } func (r *RunnerV2) _updateTaskStat(status string) { ts, err := client.NewModelServiceV2[models2.TaskStatV2]().GetById(r.tid) if err != nil { trace.PrintError(err) return } switch status { case constants.TaskStatusPending: // do nothing case constants.TaskStatusRunning: ts.StartTs = time.Now() ts.WaitDuration = ts.StartTs.Sub(ts.BaseModelV2.CreatedAt).Milliseconds() case constants.TaskStatusFinished, constants.TaskStatusError, constants.TaskStatusCancelled: if ts.StartTs.IsZero() { ts.StartTs = time.Now() ts.WaitDuration = ts.StartTs.Sub(ts.BaseModelV2.CreatedAt).Milliseconds() } ts.EndTs = time.Now() ts.RuntimeDuration = ts.EndTs.Sub(ts.StartTs).Milliseconds() ts.TotalDuration = ts.EndTs.Sub(ts.BaseModelV2.CreatedAt).Milliseconds() } if r.svc.GetNodeConfigService().IsMaster() { err = service2.NewModelServiceV2[models2.TaskStatV2]().ReplaceById(ts.Id, *ts) if err != nil { trace.PrintError(err) return } } else { err = client.NewModelServiceV2[models2.TaskStatV2]().ReplaceById(ts.Id, *ts) if err != nil { trace.PrintError(err) return } } } func (r *RunnerV2) sendNotification() { req := &grpc.TaskServiceSendNotificationRequest{ NodeKey: r.svc.GetNodeConfigService().GetNodeKey(), TaskId: r.tid.Hex(), } _, err := r.c.TaskClient.SendNotification(context.Background(), req) if err != nil { log.Errorf("Error sending notification: %v", err) trace.PrintError(err) return } } func (r *RunnerV2) _updateSpiderStat(status string) { // task stat ts, err := client.NewModelServiceV2[models2.TaskStatV2]().GetById(r.tid) if err != nil { trace.PrintError(err) return } // update var update bson.M switch status { case constants.TaskStatusPending, constants.TaskStatusRunning: update = bson.M{ "$set": bson.M{ "last_task_id": r.tid, // last task id }, "$inc": bson.M{ "tasks": 1, // task count "wait_duration": ts.WaitDuration, // wait duration }, } case constants.TaskStatusFinished, constants.TaskStatusError, constants.TaskStatusCancelled: update = bson.M{ "$set": bson.M{ "last_task_id": r.tid, // last task id }, "$inc": bson.M{ "results": ts.ResultCount, // results "runtime_duration": ts.RuntimeDuration / 1000, // runtime duration "total_duration": ts.TotalDuration / 1000, // total duration }, } default: log.Errorf("Invalid task status: %s", status) trace.PrintError(errors.New("invalid task status")) return } // perform update if r.svc.GetNodeConfigService().IsMaster() { err = service2.NewModelServiceV2[models2.SpiderStatV2]().UpdateById(r.s.Id, update) if err != nil { trace.PrintError(err) return } } else { err = client.NewModelServiceV2[models2.SpiderStatV2]().UpdateById(r.s.Id, update) if err != nil { trace.PrintError(err) return } } } func (r *RunnerV2) configureCwd() { workspacePath := viper.GetString("workspace") if r.s.GitId.IsZero() { // not git r.cwd = filepath.Join(workspacePath, r.s.Id.Hex()) } else { // git r.cwd = filepath.Join(workspacePath, r.s.GitId.Hex(), r.s.GitRootPath) } } func NewTaskRunnerV2(id primitive.ObjectID, svc *ServiceV2) (r2 *RunnerV2, err error) { // validate options if id.IsZero() { return nil, constants.ErrInvalidOptions } // runner r := &RunnerV2{ subscribeTimeout: 30 * time.Second, bufferSize: 1024 * 1024, svc: svc, tid: id, ch: make(chan constants.TaskSignal), logBatchSize: 20, } // task r.t, err = svc.GetTaskById(id) if err != nil { return nil, err } // spider r.s, err = svc.GetSpiderById(r.t.SpiderId) if err != nil { return nil, err } // task fs service r.fsSvc = fs2.NewFsServiceV2(filepath.Join(viper.GetString("workspace"), r.s.Id.Hex())) // grpc client r.c = client2.GetGrpcClientV2() // initialize task runner if err := r.Init(); err != nil { return r, err } return r, nil } ================================================ FILE: core/task/handler/service_v2.go ================================================ package handler import ( "context" "encoding/json" "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" errors2 "github.com/crawlab-team/crawlab/core/errors" grpcclient "github.com/crawlab-team/crawlab/core/grpc/client" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/client" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "sync" "time" ) type ServiceV2 struct { // dependencies cfgSvc interfaces.NodeConfigService c *grpcclient.GrpcClientV2 // grpc client // settings //maxRunners int exitWatchDuration time.Duration reportInterval time.Duration fetchInterval time.Duration fetchTimeout time.Duration cancelTimeout time.Duration // internals variables stopped bool mu sync.Mutex runners sync.Map // pool of task runners started syncLocks sync.Map // files sync locks map of task runners } func (svc *ServiceV2) Start() { // Initialize gRPC if not started if !svc.c.IsStarted() { err := svc.c.Start() if err != nil { return } } go svc.ReportStatus() go svc.Fetch() } func (svc *ServiceV2) Run(taskId primitive.ObjectID) (err error) { return svc.run(taskId) } func (svc *ServiceV2) Reset() { svc.mu.Lock() defer svc.mu.Unlock() } func (svc *ServiceV2) Cancel(taskId primitive.ObjectID) (err error) { r, err := svc.getRunner(taskId) if err != nil { return err } if err := r.Cancel(); err != nil { return err } return nil } func (svc *ServiceV2) Fetch() { ticker := time.NewTicker(svc.fetchInterval) for { // wait <-ticker.C // current node n, err := svc.GetCurrentNode() if err != nil { continue } // skip if node is not active or enabled if !n.Active || !n.Enabled { continue } // validate if there are available runners if svc.getRunnerCount() >= n.MaxRunners { continue } // stop if svc.stopped { ticker.Stop() return } // fetch task tid, err := svc.fetch() if err != nil { trace.PrintError(err) continue } // skip if no task id if tid.IsZero() { continue } // run task if err := svc.run(tid); err != nil { trace.PrintError(err) t, err := svc.GetTaskById(tid) if err != nil && t.Status != constants.TaskStatusCancelled { t.Error = err.Error() t.Status = constants.TaskStatusError t.SetUpdated(t.CreatedBy) _ = client.NewModelServiceV2[models2.TaskV2]().ReplaceById(t.Id, *t) continue } continue } } } func (svc *ServiceV2) ReportStatus() { for { if svc.stopped { return } // report handler status if err := svc.reportStatus(); err != nil { trace.PrintError(err) } // wait time.Sleep(svc.reportInterval) } } func (svc *ServiceV2) IsSyncLocked(path string) (ok bool) { _, ok = svc.syncLocks.Load(path) return ok } func (svc *ServiceV2) LockSync(path string) { svc.syncLocks.Store(path, true) } func (svc *ServiceV2) UnlockSync(path string) { svc.syncLocks.Delete(path) } //func (svc *ServiceV2) GetMaxRunners() (maxRunners int) { // return svc.maxRunners //} // //func (svc *ServiceV2) SetMaxRunners(maxRunners int) { // svc.maxRunners = maxRunners //} func (svc *ServiceV2) GetExitWatchDuration() (duration time.Duration) { return svc.exitWatchDuration } func (svc *ServiceV2) SetExitWatchDuration(duration time.Duration) { svc.exitWatchDuration = duration } func (svc *ServiceV2) GetFetchInterval() (interval time.Duration) { return svc.fetchInterval } func (svc *ServiceV2) SetFetchInterval(interval time.Duration) { svc.fetchInterval = interval } func (svc *ServiceV2) GetReportInterval() (interval time.Duration) { return svc.reportInterval } func (svc *ServiceV2) SetReportInterval(interval time.Duration) { svc.reportInterval = interval } func (svc *ServiceV2) GetCancelTimeout() (timeout time.Duration) { return svc.cancelTimeout } func (svc *ServiceV2) SetCancelTimeout(timeout time.Duration) { svc.cancelTimeout = timeout } func (svc *ServiceV2) GetNodeConfigService() (cfgSvc interfaces.NodeConfigService) { return svc.cfgSvc } func (svc *ServiceV2) GetCurrentNode() (n *models2.NodeV2, err error) { // node key nodeKey := svc.cfgSvc.GetNodeKey() // current node if svc.cfgSvc.IsMaster() { n, err = service.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": nodeKey}, nil) } else { n, err = client.NewModelServiceV2[models2.NodeV2]().GetOne(bson.M{"key": nodeKey}, nil) } if err != nil { return nil, err } return n, nil } func (svc *ServiceV2) GetTaskById(id primitive.ObjectID) (t *models2.TaskV2, err error) { if svc.cfgSvc.IsMaster() { t, err = service.NewModelServiceV2[models2.TaskV2]().GetById(id) } else { t, err = client.NewModelServiceV2[models2.TaskV2]().GetById(id) } if err != nil { return nil, err } return t, nil } func (svc *ServiceV2) GetSpiderById(id primitive.ObjectID) (s *models2.SpiderV2, err error) { if svc.cfgSvc.IsMaster() { s, err = service.NewModelServiceV2[models2.SpiderV2]().GetById(id) } else { s, err = client.NewModelServiceV2[models2.SpiderV2]().GetById(id) } if err != nil { return nil, err } return s, nil } func (svc *ServiceV2) getRunners() (runners []*RunnerV2) { svc.mu.Lock() defer svc.mu.Unlock() svc.runners.Range(func(key, value interface{}) bool { r := value.(RunnerV2) runners = append(runners, &r) return true }) return runners } func (svc *ServiceV2) getRunnerCount() (count int) { n, err := svc.GetCurrentNode() if err != nil { trace.PrintError(err) return } query := bson.M{ "node_id": n.Id, "status": constants.TaskStatusRunning, } if svc.cfgSvc.IsMaster() { count, err = service.NewModelServiceV2[models2.TaskV2]().Count(query) if err != nil { trace.PrintError(err) return } } else { count, err = client.NewModelServiceV2[models2.TaskV2]().Count(query) if err != nil { trace.PrintError(err) return } } return count } func (svc *ServiceV2) getRunner(taskId primitive.ObjectID) (r interfaces.TaskRunner, err error) { log.Debugf("[TaskHandlerService] getRunner: taskId[%v]", taskId) v, ok := svc.runners.Load(taskId) if !ok { return nil, trace.TraceError(errors2.ErrorTaskNotExists) } switch v.(type) { case interfaces.TaskRunner: r = v.(interfaces.TaskRunner) default: return nil, trace.TraceError(errors2.ErrorModelInvalidType) } return r, nil } func (svc *ServiceV2) addRunner(taskId primitive.ObjectID, r interfaces.TaskRunner) { log.Debugf("[TaskHandlerService] addRunner: taskId[%v]", taskId) svc.runners.Store(taskId, r) } func (svc *ServiceV2) deleteRunner(taskId primitive.ObjectID) { log.Debugf("[TaskHandlerService] deleteRunner: taskId[%v]", taskId) svc.runners.Delete(taskId) } func (svc *ServiceV2) reportStatus() (err error) { // current node n, err := svc.GetCurrentNode() if err != nil { return err } // available runners of handler ar := n.MaxRunners - svc.getRunnerCount() // set available runners n.AvailableRunners = ar // save node n.SetUpdated(n.CreatedBy) if svc.cfgSvc.IsMaster() { err = service.NewModelServiceV2[models2.NodeV2]().ReplaceById(n.Id, *n) } else { err = client.NewModelServiceV2[models2.NodeV2]().ReplaceById(n.Id, *n) } if err != nil { return err } return nil } func (svc *ServiceV2) fetch() (tid primitive.ObjectID, err error) { ctx, cancel := context.WithTimeout(context.Background(), svc.fetchTimeout) defer cancel() res, err := svc.c.TaskClient.Fetch(ctx, svc.c.NewRequest(nil)) if err != nil { return tid, trace.TraceError(err) } if err := json.Unmarshal(res.Data, &tid); err != nil { return tid, trace.TraceError(err) } return tid, nil } func (svc *ServiceV2) run(taskId primitive.ObjectID) (err error) { // attempt to get runner from pool _, ok := svc.runners.Load(taskId) if ok { return trace.TraceError(errors2.ErrorTaskAlreadyExists) } // create a new task runner r, err := NewTaskRunnerV2(taskId, svc) if err != nil { return trace.TraceError(err) } // add runner to pool svc.addRunner(taskId, r) // create a goroutine to run task go func() { // delete runner from pool defer svc.deleteRunner(r.GetTaskId()) defer func(r interfaces.TaskRunner) { err := r.CleanUp() if err != nil { log.Errorf("task[%s] clean up error: %v", r.GetTaskId().Hex(), err) } }(r) // run task process (blocking) // error or finish after task runner ends if err := r.Run(); err != nil { switch { case errors.Is(err, constants.ErrTaskError): log.Errorf("task[%s] finished with error: %v", r.GetTaskId().Hex(), err) case errors.Is(err, constants.ErrTaskCancelled): log.Errorf("task[%s] cancelled", r.GetTaskId().Hex()) default: log.Errorf("task[%s] finished with unknown error: %v", r.GetTaskId().Hex(), err) } } log.Infof("task[%s] finished", r.GetTaskId().Hex()) }() return nil } func newTaskHandlerServiceV2() (svc2 *ServiceV2, err error) { // service svc := &ServiceV2{ exitWatchDuration: 60 * time.Second, fetchInterval: 1 * time.Second, fetchTimeout: 15 * time.Second, reportInterval: 5 * time.Second, cancelTimeout: 5 * time.Second, mu: sync.Mutex{}, runners: sync.Map{}, syncLocks: sync.Map{}, } // dependency injection svc.cfgSvc = nodeconfig.GetNodeConfigService() // grpc client svc.c = grpcclient.GetGrpcClientV2() log.Debugf("[NewTaskHandlerService] svc[cfgPath: %s]", svc.cfgSvc.GetConfigPath()) return svc, nil } var _serviceV2 *ServiceV2 var _serviceV2Once = new(sync.Once) func GetTaskHandlerServiceV2() (svr *ServiceV2, err error) { if _serviceV2 != nil { return _serviceV2, nil } _serviceV2Once.Do(func() { _serviceV2, err = newTaskHandlerServiceV2() if err != nil { log.Errorf("failed to create task handler service: %v", err) } }) if err != nil { return nil, err } return _serviceV2, nil } ================================================ FILE: core/task/log/constants.go ================================================ package log const ( MetadataName = "metadata.json" ) const ( DriverTypeFile = "file" // raw file DriverTypeFs = "fs" // file system (SeaweedFS) DriverTypeMongo = "mongo" // mongodb DriverTypeEs = "es" // elastic search ) ================================================ FILE: core/task/log/default.go ================================================ package log import "time" var DefaultLogTtl = 30 * 24 * time.Hour ================================================ FILE: core/task/log/driver.go ================================================ package log func GetLogDriver(logDriverType string) (driver Driver, err error) { switch logDriverType { case DriverTypeFile: driver, err = GetFileLogDriver() if err != nil { return driver, err } case DriverTypeMongo: return driver, ErrNotImplemented case DriverTypeEs: return driver, ErrNotImplemented default: return driver, ErrInvalidType } return driver, nil } ================================================ FILE: core/task/log/entity.go ================================================ package log import "time" type Message struct { Id int64 `json:"id" bson:"id"` Msg string `json:"msg" bson:"msg"` Ts time.Time `json:"ts" bson:"ts"` } type Metadata struct { Size int64 `json:"size,omitempty" bson:"size"` TotalLines int64 `json:"total_lines,omitempty" bson:"total_lines"` TotalBytes int64 `json:"total_bytes,omitempty" bson:"total_bytes"` Md5 string `json:"md5,omitempty" bson:"md5"` } ================================================ FILE: core/task/log/errors.go ================================================ package log import "errors" var ( ErrInvalidType = errors.New("invalid type") ErrNotImplemented = errors.New("not implemented") ) ================================================ FILE: core/task/log/file_driver.go ================================================ package log import ( "bufio" "bytes" "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "io" "os" "path/filepath" "strconv" "strings" "sync" "time" ) type FileLogDriver struct { // settings logFileName string rootPath string // internals mu sync.Mutex } func (d *FileLogDriver) Init() (err error) { go d.cleanup() return nil } func (d *FileLogDriver) Close() (err error) { return nil } func (d *FileLogDriver) WriteLine(id string, line string) (err error) { d.initDir(id) d.mu.Lock() defer d.mu.Unlock() filePath := d.getLogFilePath(id, d.logFileName) f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0760)) if err != nil { return trace.TraceError(err) } defer func(f *os.File) { err := f.Close() if err != nil { log.Errorf("close file error: %s", err.Error()) } }(f) _, err = f.WriteString(line + "\n") if err != nil { return trace.TraceError(err) } return nil } func (d *FileLogDriver) WriteLines(id string, lines []string) (err error) { linesString := strings.Join(lines, "\n") if err := d.WriteLine(id, linesString); err != nil { return err } return nil } func (d *FileLogDriver) Find(id string, pattern string, skip int, limit int) (lines []string, err error) { if pattern != "" { return lines, errors.New("not implemented") } if !utils.Exists(d.getLogFilePath(id, d.logFileName)) { return nil, nil } f, err := os.Open(d.getLogFilePath(id, d.logFileName)) if err != nil { return nil, trace.TraceError(err) } defer f.Close() sc := bufio.NewReaderSize(f, 1024*1024*10) i := -1 for { line, err := sc.ReadString(byte('\n')) if err != nil { break } line = strings.TrimSuffix(line, "\n") i++ if i < skip { continue } if i >= skip+limit { break } lines = append(lines, line) } return lines, nil } func (d *FileLogDriver) Count(id string, pattern string) (n int, err error) { if pattern != "" { return n, errors.New("not implemented") } if !utils.Exists(d.getLogFilePath(id, d.logFileName)) { return 0, nil } f, err := os.Open(d.getLogFilePath(id, d.logFileName)) if err != nil { return n, trace.TraceError(err) } return d.lineCounter(f) } func (d *FileLogDriver) Flush() (err error) { return nil } func (d *FileLogDriver) getLogPath() (logPath string) { return viper.GetString("log.path") } func (d *FileLogDriver) getBasePath(id string) (filePath string) { return filepath.Join(d.getLogPath(), id) } func (d *FileLogDriver) getMetadataPath(id string) (filePath string) { return filepath.Join(d.getBasePath(id), MetadataName) } func (d *FileLogDriver) getLogFilePath(id, fileName string) (filePath string) { return filepath.Join(d.getBasePath(id), fileName) } func (d *FileLogDriver) getLogFiles(id string) (files []os.FileInfo) { // 增加了对返回异常的捕获 files, err := utils.ListDir(d.getBasePath(id)) if err != nil { trace.PrintError(err) return nil } return } func (d *FileLogDriver) initDir(id string) { if !utils.Exists(d.getBasePath(id)) { if err := os.MkdirAll(d.getBasePath(id), os.FileMode(0770)); err != nil { trace.PrintError(err) } } } func (d *FileLogDriver) lineCounter(r io.Reader) (n int, err error) { buf := make([]byte, 32*1024) count := 0 lineSep := []byte{'\n'} for { c, err := r.Read(buf) count += bytes.Count(buf[:c], lineSep) switch { case err == io.EOF: return count, nil case err != nil: return count, err } } } func (d *FileLogDriver) getTtl() time.Duration { ttl := viper.GetString("log.ttl") if ttl == "" { return DefaultLogTtl } if strings.HasSuffix(ttl, "s") { ttl = strings.TrimSuffix(ttl, "s") n, err := strconv.Atoi(ttl) if err != nil { return DefaultLogTtl } return time.Duration(n) * time.Second } else if strings.HasSuffix(ttl, "m") { ttl = strings.TrimSuffix(ttl, "m") n, err := strconv.Atoi(ttl) if err != nil { return DefaultLogTtl } return time.Duration(n) * time.Minute } else if strings.HasSuffix(ttl, "h") { ttl = strings.TrimSuffix(ttl, "h") n, err := strconv.Atoi(ttl) if err != nil { return DefaultLogTtl } return time.Duration(n) * time.Hour } else if strings.HasSuffix(ttl, "d") { ttl = strings.TrimSuffix(ttl, "d") n, err := strconv.Atoi(ttl) if err != nil { return DefaultLogTtl } return time.Duration(n) * 24 * time.Hour } else { return DefaultLogTtl } } func (d *FileLogDriver) cleanup() { if d.getLogPath() == "" { return } if !utils.Exists(d.getLogPath()) { if err := os.MkdirAll(d.getLogPath(), os.FileMode(0770)); err != nil { log.Errorf("failed to create log directory: %s", d.getLogPath()) trace.PrintError(err) return } } for { // 增加对目录不存在的判断 dirs, err := utils.ListDir(d.getLogPath()) if err != nil { trace.PrintError(err) time.Sleep(10 * time.Minute) continue } for _, dir := range dirs { if time.Now().After(dir.ModTime().Add(d.getTtl())) { if err := os.RemoveAll(d.getBasePath(dir.Name())); err != nil { trace.PrintError(err) continue } log.Infof("removed outdated log directory: %s", d.getBasePath(dir.Name())) } } time.Sleep(10 * time.Minute) } } var logDriver Driver func newFileLogDriver() (driver Driver, err error) { // driver driver = &FileLogDriver{ logFileName: "log.txt", mu: sync.Mutex{}, } // init if err := driver.Init(); err != nil { return nil, err } return driver, nil } func GetFileLogDriver() (driver Driver, err error) { if logDriver != nil { return logDriver, nil } logDriver, err = newFileLogDriver() if err != nil { return nil, err } return logDriver, nil } ================================================ FILE: core/task/log/file_driver_test.go ================================================ package log import ( "fmt" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson/primitive" "os" "strings" "testing" ) func setupFileDriverTest() { cleanupFileDriverTest() _ = os.MkdirAll("./tmp", os.ModePerm) } func cleanupFileDriverTest() { _ = os.RemoveAll("./tmp") } func TestFileDriver_WriteLine(t *testing.T) { setupFileDriverTest() t.Cleanup(cleanupFileDriverTest) d, err := newFileLogDriver(nil) require.Nil(t, err) defer d.Close() id := primitive.NewObjectID() err = d.WriteLine(id.Hex(), "it works") require.Nil(t, err) logFilePath := fmt.Sprintf("/var/log/crawlab/%s/log.txt", id.Hex()) require.FileExists(t, logFilePath) text, err := os.ReadFile(logFilePath) require.Nil(t, err) require.Equal(t, "it works\n", string(text)) } func TestFileDriver_WriteLines(t *testing.T) { setupFileDriverTest() t.Cleanup(cleanupFileDriverTest) d, err := newFileLogDriver(nil) require.Nil(t, err) defer d.Close() id := primitive.NewObjectID() for i := 0; i < 100; i++ { err = d.WriteLine(id.Hex(), "it works") require.Nil(t, err) } logFilePath := fmt.Sprintf("/var/log/crawlab/%s/log.txt", id.Hex()) require.FileExists(t, logFilePath) text, err := os.ReadFile(logFilePath) require.Nil(t, err) require.Contains(t, string(text), "it works\n") lines := strings.Split(string(text), "\n") require.Equal(t, 101, len(lines)) } func TestFileDriver_Find(t *testing.T) { setupFileDriverTest() t.Cleanup(cleanupFileDriverTest) d, err := newFileLogDriver(nil) require.Nil(t, err) defer d.Close() id := primitive.NewObjectID() batch := 1000 var lines []string for i := 0; i < 10; i++ { for j := 0; j < batch; j++ { line := fmt.Sprintf("line: %d", i*batch+j+1) lines = append(lines, line) } err = d.WriteLines(id.Hex(), lines) require.Nil(t, err) lines = []string{} } driver := d lines, err = driver.Find(id.Hex(), "", 0, 10) require.Nil(t, err) require.Equal(t, 10, len(lines)) require.Equal(t, "line: 1", lines[0]) require.Equal(t, "line: 10", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 0, 1) require.Nil(t, err) require.Equal(t, 1, len(lines)) require.Equal(t, "line: 1", lines[0]) require.Equal(t, "line: 1", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 0, 1000) require.Nil(t, err) require.Equal(t, 1000, len(lines)) require.Equal(t, "line: 1", lines[0]) require.Equal(t, "line: 1000", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 1000, 1000) require.Nil(t, err) require.Equal(t, 1000, len(lines)) require.Equal(t, "line: 1001", lines[0]) require.Equal(t, "line: 2000", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 1001, 1000) require.Nil(t, err) require.Equal(t, 1000, len(lines)) require.Equal(t, "line: 1002", lines[0]) require.Equal(t, "line: 2001", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 1001, 999) require.Nil(t, err) require.Equal(t, 999, len(lines)) require.Equal(t, "line: 1002", lines[0]) require.Equal(t, "line: 2000", lines[len(lines)-1]) lines, err = driver.Find(id.Hex(), "", 999, 2001) require.Nil(t, err) require.Equal(t, 2001, len(lines)) require.Equal(t, "line: 1000", lines[0]) require.Equal(t, "line: 3000", lines[len(lines)-1]) cleanupFileDriverTest() } ================================================ FILE: core/task/log/interface.go ================================================ package log type Driver interface { Init() (err error) Close() (err error) WriteLine(id string, line string) (err error) WriteLines(id string, lines []string) (err error) Find(id string, pattern string, skip int, limit int) (lines []string, err error) Count(id string, pattern string) (n int, err error) } ================================================ FILE: core/task/scheduler/options.go ================================================ package scheduler import ( "github.com/crawlab-team/crawlab/core/interfaces" "time" ) type Option func(svc interfaces.TaskSchedulerService) func WithConfigPath(path string) Option { return func(svc interfaces.TaskSchedulerService) { svc.SetConfigPath(path) } } func WithInterval(interval time.Duration) Option { return func(svc interfaces.TaskSchedulerService) { svc.SetInterval(interval) } } ================================================ FILE: core/task/scheduler/service_v2.go ================================================ package scheduler import ( errors2 "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/grpc/server" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/task/handler" "github.com/crawlab-team/crawlab/core/utils" grpc "github.com/crawlab-team/crawlab/grpc" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" mongo2 "go.mongodb.org/mongo-driver/mongo" "time" ) type ServiceV2 struct { // dependencies nodeCfgSvc interfaces.NodeConfigService svr *server.GrpcServerV2 handlerSvc *handler.ServiceV2 // settings interval time.Duration } func (svc *ServiceV2) Start() { go svc.initTaskStatus() go svc.cleanupTasks() utils.DefaultWait() } func (svc *ServiceV2) Enqueue(t *models2.TaskV2, by primitive.ObjectID) (t2 *models2.TaskV2, err error) { // set task status t.Status = constants.TaskStatusPending t.SetCreated(by) t.SetUpdated(by) // add task taskModelSvc := service.NewModelServiceV2[models2.TaskV2]() id, err := taskModelSvc.InsertOne(*t) if err != nil { return nil, err } // task queue item tq := models2.TaskQueueItemV2{ Priority: t.Priority, NodeId: t.NodeId, } tq.SetId(id) tq.SetCreated(by) tq.SetUpdated(by) // task stat ts := models2.TaskStatV2{} ts.SetId(id) ts.SetCreated(by) ts.SetUpdated(by) // enqueue task _, err = service.NewModelServiceV2[models2.TaskQueueItemV2]().InsertOne(tq) if err != nil { return nil, trace.TraceError(err) } // add task stat _, err = service.NewModelServiceV2[models2.TaskStatV2]().InsertOne(ts) if err != nil { return nil, trace.TraceError(err) } // success return t, nil } func (svc *ServiceV2) Cancel(id primitive.ObjectID, by primitive.ObjectID) (err error) { // task t, err := service.NewModelServiceV2[models2.TaskV2]().GetById(id) if err != nil { return trace.TraceError(err) } // initial status initialStatus := t.Status // set task status as "cancelled" t.Status = constants.TaskStatusCancelled _ = svc.SaveTask(t, by) // set status of pending tasks as "cancelled" and remove from task item queue if initialStatus == constants.TaskStatusPending { // remove from task item queue if err := service.NewModelServiceV2[models2.TaskQueueItemV2]().DeleteById(t.Id); err != nil { return trace.TraceError(err) } return nil } // whether task is running on master node isMasterTask, err := svc.isMasterNode(t) if err != nil { // when error, force status being set as "cancelled" t.Status = constants.TaskStatusCancelled return svc.SaveTask(t, by) } // node n, err := service.NewModelServiceV2[models2.NodeV2]().GetById(t.NodeId) if err != nil { return trace.TraceError(err) } if isMasterTask { // cancel task on master if err := svc.handlerSvc.Cancel(id); err != nil { return trace.TraceError(err) } // cancel success return nil } else { // send to cancel task on worker nodes if err := svc.svr.SendStreamMessageWithData("node:"+n.Key, grpc.StreamMessageCode_CANCEL_TASK, t); err != nil { return trace.TraceError(err) } // cancel success return nil } } func (svc *ServiceV2) SetInterval(interval time.Duration) { svc.interval = interval } func (svc *ServiceV2) SaveTask(t *models2.TaskV2, by primitive.ObjectID) (err error) { if t.Id.IsZero() { t.SetCreated(by) t.SetUpdated(by) _, err = service.NewModelServiceV2[models2.TaskV2]().InsertOne(*t) return err } else { t.SetUpdated(by) return service.NewModelServiceV2[models2.TaskV2]().ReplaceById(t.Id, *t) } } // initTaskStatus initialize task status of existing tasks func (svc *ServiceV2) initTaskStatus() { // set status of running tasks as TaskStatusAbnormal runningTasks, err := service.NewModelServiceV2[models2.TaskV2]().GetMany(bson.M{ "status": bson.M{ "$in": []string{ constants.TaskStatusPending, constants.TaskStatusRunning, }, }, }, nil) if err != nil { if errors2.Is(err, mongo2.ErrNoDocuments) { return } trace.PrintError(err) } for _, t := range runningTasks { go func(t *models2.TaskV2) { t.Status = constants.TaskStatusAbnormal if err := svc.SaveTask(t, primitive.NilObjectID); err != nil { trace.PrintError(err) } }(&t) } if err := service.NewModelServiceV2[models2.TaskQueueItemV2]().DeleteMany(nil); err != nil { return } } func (svc *ServiceV2) isMasterNode(t *models2.TaskV2) (ok bool, err error) { if t.NodeId.IsZero() { return false, trace.TraceError(errors.ErrorTaskNoNodeId) } n, err := service.NewModelServiceV2[models2.NodeV2]().GetById(t.NodeId) if err != nil { if errors2.Is(err, mongo2.ErrNoDocuments) { return false, trace.TraceError(errors.ErrorTaskNodeNotFound) } return false, trace.TraceError(err) } return n.IsMaster, nil } func (svc *ServiceV2) cleanupTasks() { for { // task stats over 30 days ago taskStats, err := service.NewModelServiceV2[models2.TaskStatV2]().GetMany(bson.M{ "create_ts": bson.M{ "$lt": time.Now().Add(-30 * 24 * time.Hour), }, }, nil) if err != nil { time.Sleep(30 * time.Minute) continue } // task ids var ids []primitive.ObjectID for _, ts := range taskStats { ids = append(ids, ts.Id) } if len(ids) > 0 { // remove tasks if err := service.NewModelServiceV2[models2.TaskV2]().DeleteMany(bson.M{ "_id": bson.M{"$in": ids}, }); err != nil { trace.PrintError(err) } // remove task stats if err := service.NewModelServiceV2[models2.TaskStatV2]().DeleteMany(bson.M{ "_id": bson.M{"$in": ids}, }); err != nil { trace.PrintError(err) } } time.Sleep(30 * time.Minute) } } func NewTaskSchedulerServiceV2() (svc2 *ServiceV2, err error) { // service svc := &ServiceV2{ interval: 5 * time.Second, } svc.nodeCfgSvc = nodeconfig.GetNodeConfigService() svc.svr, err = server.GetGrpcServerV2() if err != nil { log.Errorf("failed to get grpc server: %v", err) return nil, err } svc.handlerSvc, err = handler.GetTaskHandlerServiceV2() if err != nil { log.Errorf("failed to get task handler service: %v", err) return nil, err } return svc, nil } var svcV2 *ServiceV2 func GetTaskSchedulerServiceV2() (svr *ServiceV2, err error) { if svcV2 != nil { return svcV2, nil } svcV2, err = NewTaskSchedulerServiceV2() if err != nil { return nil, err } return svcV2, nil } ================================================ FILE: core/task/stats/options.go ================================================ package stats import "github.com/crawlab-team/crawlab/core/interfaces" type Option func(service interfaces.TaskStatsService) func WithConfigPath(path string) Option { return func(svc interfaces.TaskStatsService) { svc.SetConfigPath(path) } } ================================================ FILE: core/task/stats/service_v2.go ================================================ package stats import ( log2 "github.com/apex/log" "github.com/crawlab-team/crawlab/core/database" interfaces2 "github.com/crawlab-team/crawlab/core/database/interfaces" "github.com/crawlab-team/crawlab/core/interfaces" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" nodeconfig "github.com/crawlab-team/crawlab/core/node/config" "github.com/crawlab-team/crawlab/core/task/log" "github.com/crawlab-team/crawlab/core/utils" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "sync" "time" ) type databaseServiceItem struct { taskId primitive.ObjectID dbId primitive.ObjectID dbSvc interfaces2.DatabaseService tableName string time time.Time } type ServiceV2 struct { // dependencies nodeCfgSvc interfaces.NodeConfigService // internals mu sync.Mutex databaseServiceItems map[string]*databaseServiceItem databaseServiceTll time.Duration logDriver log.Driver } func (svc *ServiceV2) Init() (err error) { go svc.cleanup() return nil } func (svc *ServiceV2) InsertData(taskId primitive.ObjectID, records ...map[string]interface{}) (err error) { count := 0 item, err := svc.getDatabaseServiceItem(taskId) if err != nil { return err } dbId := item.dbId dbSvc := item.dbSvc tableName := item.tableName if utils.IsPro() && dbSvc != nil { for _, record := range records { if err := dbSvc.CreateRow(dbId, "", tableName, record); err != nil { log2.Errorf("failed to insert data: %v", err) continue } count++ } } else { var records2 []interface{} for _, record := range records { records2 = append(records2, record) } _, err = mongo.GetMongoCol(tableName).InsertMany(records2) if err != nil { log2.Errorf("failed to insert data: %v", err) return err } count = len(records) } go svc.updateTaskStats(taskId, count) return nil } func (svc *ServiceV2) InsertLogs(id primitive.ObjectID, logs ...string) (err error) { return svc.logDriver.WriteLines(id.Hex(), logs) } func (svc *ServiceV2) getDatabaseServiceItem(taskId primitive.ObjectID) (item *databaseServiceItem, err error) { // atomic operation svc.mu.Lock() defer svc.mu.Unlock() // attempt to get from cache item, ok := svc.databaseServiceItems[taskId.Hex()] if ok { // hit in cache item.time = time.Now() return item, nil } // task t, err := service.NewModelServiceV2[models2.TaskV2]().GetById(taskId) if err != nil { return nil, err } // spider s, err := service.NewModelServiceV2[models2.SpiderV2]().GetById(t.SpiderId) if err != nil { return nil, err } // database service var dbSvc interfaces2.DatabaseService if utils.IsPro() { if dbRegSvc := database.GetDatabaseRegistryService(); dbRegSvc != nil { dbSvc, err = dbRegSvc.GetDatabaseService(s.DataSourceId) if err != nil { return nil, err } } } // store in cache svc.databaseServiceItems[taskId.Hex()] = &databaseServiceItem{ taskId: taskId, dbId: s.DataSourceId, dbSvc: dbSvc, tableName: s.ColName, time: time.Now(), } return item, nil } func (svc *ServiceV2) updateTaskStats(id primitive.ObjectID, resultCount int) { err := service.NewModelServiceV2[models2.TaskStatV2]().UpdateById(id, bson.M{ "$inc": bson.M{ "result_count": resultCount, }, }) if err != nil { trace.PrintError(err) } } func (svc *ServiceV2) cleanup() { for { // atomic operation svc.mu.Lock() for k, v := range svc.databaseServiceItems { if time.Now().After(v.time.Add(svc.databaseServiceTll)) { delete(svc.databaseServiceItems, k) } } svc.mu.Unlock() time.Sleep(10 * time.Minute) } } func NewTaskStatsServiceV2() (svc2 *ServiceV2, err error) { // service svc := &ServiceV2{ mu: sync.Mutex{}, databaseServiceItems: map[string]*databaseServiceItem{}, databaseServiceTll: 10 * time.Minute, } svc.nodeCfgSvc = nodeconfig.GetNodeConfigService() // log driver svc.logDriver, err = log.GetLogDriver(log.DriverTypeFile) if err != nil { return nil, err } return svc, nil } var _serviceV2 *ServiceV2 func GetTaskStatsServiceV2() (svr *ServiceV2, err error) { if _serviceV2 != nil { return _serviceV2, nil } _serviceV2, err = NewTaskStatsServiceV2() if err != nil { return nil, err } return _serviceV2, nil } ================================================ FILE: core/user/options.go ================================================ package user import "github.com/crawlab-team/crawlab/core/interfaces" type Option func(svc interfaces.UserService) func WithJwtSecret(secret string) Option { return func(svc interfaces.UserService) { svc.SetJwtSecret(secret) } } ================================================ FILE: core/user/service.go ================================================ package user import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/container" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/delegate" "github.com/crawlab-team/crawlab/core/models/models" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" mongo2 "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "time" ) type Service struct { // settings variables jwtSecret string jwtSigningMethod jwt.SigningMethod // dependencies modelSvc service.ModelService } func (svc *Service) Init() (err error) { _, err = svc.modelSvc.GetUserByUsername(constants.DefaultAdminUsername, nil) if err == nil { return nil } if err.Error() != mongo.ErrNoDocuments.Error() { return err } return svc.Create(&interfaces.UserCreateOptions{ Username: constants.DefaultAdminUsername, Password: constants.DefaultAdminPassword, Role: constants.RoleAdmin, }) } func (svc *Service) SetJwtSecret(secret string) { svc.jwtSecret = secret } func (svc *Service) SetJwtSigningMethod(method jwt.SigningMethod) { svc.jwtSigningMethod = method } func (svc *Service) Create(opts *interfaces.UserCreateOptions, args ...interface{}) (err error) { actor := utils.GetUserFromArgs(args...) // validate options if opts.Username == "" || opts.Password == "" { return trace.TraceError(errors.ErrorUserMissingRequiredFields) } if len(opts.Password) < 5 { return trace.TraceError(errors.ErrorUserInvalidPassword) } // normalize options if opts.Role == "" { opts.Role = constants.RoleNormal } // check if user exists if u, err := svc.modelSvc.GetUserByUsername(opts.Username, nil); err == nil && u != nil && !u.Id.IsZero() { return trace.TraceError(errors.ErrorUserAlreadyExists) } // transaction return mongo2.RunTransaction(func(ctx mongo.SessionContext) error { // add user u := &models.User{ Username: opts.Username, Role: opts.Role, Email: opts.Email, } if err := delegate.NewModelDelegate(u, actor).Add(); err != nil { return err } // add password p := &models.Password{ Id: u.Id, Password: utils.EncryptMd5(opts.Password), } if err := delegate.NewModelDelegate(p, actor).Add(); err != nil { return err } return nil }) } func (svc *Service) Login(opts *interfaces.UserLoginOptions) (token string, u interfaces.User, err error) { u, err = svc.modelSvc.GetUserByUsername(opts.Username, nil) if err != nil { return "", nil, err } p, err := svc.modelSvc.GetPasswordById(u.GetId()) if err != nil { return "", nil, err } if p.Password != utils.EncryptMd5(opts.Password) { return "", nil, errors.ErrorUserMismatch } token, err = svc.makeToken(u) if err != nil { return "", nil, err } return token, u, nil } func (svc *Service) CheckToken(tokenStr string) (u interfaces.User, err error) { return svc.checkToken(tokenStr) } func (svc *Service) ChangePassword(id primitive.ObjectID, password string, args ...interface{}) (err error) { actor := utils.GetUserFromArgs(args...) p, err := svc.modelSvc.GetPasswordById(id) if err != nil { return err } p.Password = utils.EncryptMd5(password) if err := delegate.NewModelDelegate(p, actor).Save(); err != nil { return err } return nil } func (svc *Service) MakeToken(user interfaces.User) (tokenStr string, err error) { return svc.makeToken(user) } func (svc *Service) GetCurrentUser(c *gin.Context) (user interfaces.User, err error) { // token string tokenStr := c.GetHeader("Authorization") // user u, err := userSvc.CheckToken(tokenStr) if err != nil { return nil, err } return u, nil } func (svc *Service) makeToken(user interfaces.User) (tokenStr string, err error) { token := jwt.NewWithClaims(svc.jwtSigningMethod, jwt.MapClaims{ "id": user.GetId(), "username": user.GetUsername(), "nbf": time.Now().Unix(), }) return token.SignedString([]byte(svc.jwtSecret)) } func (svc *Service) checkToken(tokenStr string) (user interfaces.User, err error) { token, err := jwt.Parse(tokenStr, svc.getSecretFunc()) if err != nil { return } claim, ok := token.Claims.(jwt.MapClaims) if !ok { err = errors.ErrorUserInvalidType return } if !token.Valid { err = errors.ErrorUserInvalidToken return } id, err := primitive.ObjectIDFromHex(claim["id"].(string)) if err != nil { return user, err } username := claim["username"].(string) user, err = svc.modelSvc.GetUserById(id) if err != nil { err = errors.ErrorUserNotExists return } if username != user.GetUsername() { err = errors.ErrorUserMismatch return } return } func (svc *Service) getSecretFunc() jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { return []byte(svc.jwtSecret), nil } } func NewUserService() (svc2 interfaces.UserService, err error) { // service svc := &Service{ jwtSecret: "crawlab", jwtSigningMethod: jwt.SigningMethodHS256, } // dependency injection if err := container.GetContainer().Invoke(func(modelSvc service.ModelService) { svc.modelSvc = modelSvc }); err != nil { return nil, trace.TraceError(err) } // initialize if err := svc.Init(); err != nil { return nil, trace.TraceError(err) } return svc, nil } var userSvc interfaces.UserService func GetUserService() (svc interfaces.UserService, err error) { if userSvc != nil { return userSvc, nil } svc, err = NewUserService() if err != nil { return nil, err } userSvc = svc return svc, nil } ================================================ FILE: core/user/service_v2.go ================================================ package user import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/utils" mongo2 "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "sync" "time" ) type ServiceV2 struct { jwtSecret string jwtSigningMethod jwt.SigningMethod modelSvc *service.ModelServiceV2[models.UserV2] } func (svc *ServiceV2) Init() (err error) { _, err = svc.modelSvc.GetOne(bson.M{"username": constants.DefaultAdminUsername}, nil) if err == nil { return nil } if err.Error() != mongo.ErrNoDocuments.Error() { return err } return svc.Create( constants.DefaultAdminUsername, constants.DefaultAdminPassword, constants.RoleAdmin, "", primitive.NilObjectID, ) } func (svc *ServiceV2) SetJwtSecret(secret string) { svc.jwtSecret = secret } func (svc *ServiceV2) SetJwtSigningMethod(method jwt.SigningMethod) { svc.jwtSigningMethod = method } func (svc *ServiceV2) Create(username, password, role, email string, by primitive.ObjectID) (err error) { // validate options if username == "" || password == "" { return trace.TraceError(errors.ErrorUserMissingRequiredFields) } if len(password) < 5 { return trace.TraceError(errors.ErrorUserInvalidPassword) } // normalize options if role == "" { role = constants.RoleNormal } // check if user exists if u, err := svc.modelSvc.GetOne(bson.M{"username": username}, nil); err == nil && u != nil && !u.Id.IsZero() { return trace.TraceError(errors.ErrorUserAlreadyExists) } // transaction return mongo2.RunTransaction(func(ctx mongo.SessionContext) error { // add user u := models.UserV2{ Username: username, Role: role, Password: utils.EncryptMd5(password), Email: email, } u.SetCreated(by) u.SetUpdated(by) _, err = svc.modelSvc.InsertOne(u) return err }) } func (svc *ServiceV2) Login(username, password string) (token string, u *models.UserV2, err error) { u, err = svc.modelSvc.GetOne(bson.M{"username": username}, nil) if err != nil { return "", nil, err } if u.Password != utils.EncryptMd5(password) { return "", nil, errors.ErrorUserMismatch } token, err = svc.makeToken(u) if err != nil { return "", nil, err } return token, u, nil } func (svc *ServiceV2) CheckToken(tokenStr string) (u *models.UserV2, err error) { return svc.checkToken(tokenStr) } func (svc *ServiceV2) ChangePassword(id primitive.ObjectID, password string, by primitive.ObjectID) (err error) { u, err := svc.modelSvc.GetById(id) if err != nil { return err } u.Password = utils.EncryptMd5(password) u.SetCreatedBy(by) return svc.modelSvc.ReplaceById(id, *u) } func (svc *ServiceV2) MakeToken(user *models.UserV2) (tokenStr string, err error) { return svc.makeToken(user) } func (svc *ServiceV2) GetCurrentUser(c *gin.Context) (user interfaces.User, err error) { // token string tokenStr := c.GetHeader("Authorization") // user u, err := userSvc.CheckToken(tokenStr) if err != nil { return nil, err } return u, nil } func (svc *ServiceV2) makeToken(user *models.UserV2) (tokenStr string, err error) { token := jwt.NewWithClaims(svc.jwtSigningMethod, jwt.MapClaims{ "id": user.Id, "username": user.Username, "nbf": time.Now().Unix(), }) return token.SignedString([]byte(svc.jwtSecret)) } func (svc *ServiceV2) checkToken(tokenStr string) (user *models.UserV2, err error) { token, err := jwt.Parse(tokenStr, svc.getSecretFunc()) if err != nil { return } claim, ok := token.Claims.(jwt.MapClaims) if !ok { err = errors.ErrorUserInvalidType return } if !token.Valid { err = errors.ErrorUserInvalidToken return } id, err := primitive.ObjectIDFromHex(claim["id"].(string)) if err != nil { return user, err } username := claim["username"].(string) user, err = svc.modelSvc.GetById(id) if err != nil { err = errors.ErrorUserNotExists return } if username != user.Username { err = errors.ErrorUserMismatch return } return } func (svc *ServiceV2) getSecretFunc() jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { return []byte(svc.jwtSecret), nil } } func newUserServiceV2() (svc *ServiceV2, err error) { // service svc = &ServiceV2{ modelSvc: service.NewModelServiceV2[models.UserV2](), jwtSecret: "crawlab", jwtSigningMethod: jwt.SigningMethodHS256, } // initialize if err := svc.Init(); err != nil { log.Errorf("failed to initialize user service: %v", err) return nil, trace.TraceError(err) } return svc, nil } var userSvcV2 *ServiceV2 var userSvcV2Once sync.Once func GetUserServiceV2() (svc *ServiceV2, err error) { userSvcV2Once.Do(func() { userSvcV2, err = newUserServiceV2() if err != nil { return } }) return userSvcV2, nil } ================================================ FILE: core/user/test/base.go ================================================ package test import ( "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/models/service" "github.com/crawlab-team/crawlab/core/user" "go.uber.org/dig" "testing" ) func init() { var err error T, err = NewTest() if err != nil { panic(err) } } var T *Test type Test struct { // dependencies modelSvc service.ModelService userSvc interfaces.UserService // test data TestUsername string TestPassword string TestNewPassword string } func (t *Test) Setup(t2 *testing.T) { var err error t.userSvc, err = user.NewUserService() if err != nil { panic(err) } t2.Cleanup(t.Cleanup) } func (t *Test) Cleanup() { _ = t.modelSvc.GetBaseService(interfaces.ModelIdUser).DeleteList(nil) } func NewTest() (t *Test, err error) { // test t = &Test{ TestUsername: "test_username", TestPassword: "test_password", TestNewPassword: "test_new_password", } // dependency injection c := dig.New() if err := c.Provide(service.GetService); err != nil { return nil, err } if err := c.Invoke(func(modelSvc service.ModelService) { t.modelSvc = modelSvc }); err != nil { return nil, err } return t, nil } ================================================ FILE: core/user/test/user_service_test.go ================================================ package test import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" "github.com/crawlab-team/crawlab/core/utils" "github.com/stretchr/testify/require" "testing" ) func TestUserService_Init(t *testing.T) { var err error T.Setup(t) u, err := T.modelSvc.GetUserByUsernameWithPassword(constants.DefaultAdminUsername, nil) require.Nil(t, err) require.Equal(t, constants.DefaultAdminUsername, u.Username) require.Equal(t, utils.EncryptMd5(constants.DefaultAdminPassword), u.Password) } func TestUserService_Create_Login_CheckToken(t *testing.T) { var err error T.Setup(t) err = T.userSvc.Create(&interfaces.UserCreateOptions{ Username: T.TestUsername, Password: T.TestPassword, }) require.Nil(t, err) u, err := T.modelSvc.GetUserByUsernameWithPassword(T.TestUsername, nil) require.Nil(t, err) require.Equal(t, T.TestUsername, u.Username) require.Equal(t, utils.EncryptMd5(T.TestPassword), u.Password) token, u2, err := T.userSvc.Login(&interfaces.UserLoginOptions{ Username: T.TestUsername, Password: T.TestPassword, }) require.Nil(t, err) require.Greater(t, len(token), 10) require.Equal(t, u.Username, u2.GetUsername()) u3, err := T.userSvc.CheckToken(token) require.Nil(t, err) require.Equal(t, u.Username, u3.GetUsername()) } func TestUserService_ChangePassword(t *testing.T) { var err error T.Setup(t) u, err := T.modelSvc.GetUserByUsernameWithPassword(constants.DefaultAdminUsername, nil) require.Nil(t, err) err = T.userSvc.ChangePassword(u.Id, T.TestNewPassword) require.Nil(t, err) u2, err := T.modelSvc.GetUserByUsernameWithPassword(constants.DefaultAdminUsername, nil) require.Nil(t, err) require.Equal(t, utils.EncryptMd5(T.TestNewPassword), u2.Password) } ================================================ FILE: core/utils/args.go ================================================ package utils import "github.com/crawlab-team/crawlab/core/interfaces" func GetUserFromArgs(args ...interface{}) (u interfaces.User) { for _, arg := range args { switch arg.(type) { case interfaces.User: var ok bool u, ok = arg.(interfaces.User) if ok { return u } } } return nil } ================================================ FILE: core/utils/array.go ================================================ package utils import ( "errors" "math/rand" "reflect" "time" ) func StringArrayContains(arr []string, str string) bool { for _, s := range arr { if s == str { return true } } return false } func GetArrayItems(array interface{}) (res []interface{}, err error) { switch reflect.TypeOf(array).Kind() { case reflect.Slice, reflect.Array: s := reflect.ValueOf(array) for i := 0; i < s.Len(); i++ { obj, ok := s.Index(i).Interface().(interface{}) if !ok { return nil, errors.New("invalid type") } res = append(res, obj) } default: return nil, errors.New("invalid type") } return res, nil } func ShuffleArray(slice []interface{}) (err error) { r := rand.New(rand.NewSource(time.Now().Unix())) for len(slice) > 0 { n := len(slice) randIndex := r.Intn(n) slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1] slice = slice[:n-1] } return nil } ================================================ FILE: core/utils/backoff.go ================================================ package utils import ( "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/trace" "time" ) func BackoffErrorNotify(prefix string) backoff.Notify { return func(err error, duration time.Duration) { log.Errorf("%s error: %v. reattempt in %.1f seconds...", prefix, err, duration.Seconds()) trace.PrintError(err) } } ================================================ FILE: core/utils/binders/binder_col_name.go ================================================ package binders import ( "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" ) func NewColNameBinder(id interfaces.ModelId) (b *ColNameBinder) { return &ColNameBinder{id: id} } type ColNameBinder struct { id interfaces.ModelId } func (b *ColNameBinder) Bind() (res interface{}, err error) { switch b.id { // system models case interfaces.ModelIdArtifact: return interfaces.ModelColNameArtifact, nil case interfaces.ModelIdTag: return interfaces.ModelColNameTag, nil // operation models case interfaces.ModelIdNode: return interfaces.ModelColNameNode, nil case interfaces.ModelIdProject: return interfaces.ModelColNameProject, nil case interfaces.ModelIdSpider: return interfaces.ModelColNameSpider, nil case interfaces.ModelIdTask: return interfaces.ModelColNameTask, nil case interfaces.ModelIdJob: return interfaces.ModelColNameJob, nil case interfaces.ModelIdSchedule: return interfaces.ModelColNameSchedule, nil case interfaces.ModelIdUser: return interfaces.ModelColNameUser, nil case interfaces.ModelIdSetting: return interfaces.ModelColNameSetting, nil case interfaces.ModelIdToken: return interfaces.ModelColNameToken, nil case interfaces.ModelIdVariable: return interfaces.ModelColNameVariable, nil case interfaces.ModelIdTaskQueue: return interfaces.ModelColNameTaskQueue, nil case interfaces.ModelIdTaskStat: return interfaces.ModelColNameTaskStat, nil case interfaces.ModelIdSpiderStat: return interfaces.ModelColNameSpiderStat, nil case interfaces.ModelIdDataSource: return interfaces.ModelColNameDataSource, nil case interfaces.ModelIdDataCollection: return interfaces.ModelColNameDataCollection, nil case interfaces.ModelIdPassword: return interfaces.ModelColNamePasswords, nil case interfaces.ModelIdExtraValue: return interfaces.ModelColNameExtraValues, nil case interfaces.ModelIdGit: return interfaces.ModelColNameGit, nil case interfaces.ModelIdRole: return interfaces.ModelColNameRole, nil case interfaces.ModelIdUserRole: return interfaces.ModelColNameUserRole, nil case interfaces.ModelIdPermission: return interfaces.ModelColNamePermission, nil case interfaces.ModelIdRolePermission: return interfaces.ModelColNameRolePermission, nil case interfaces.ModelIdEnvironment: return interfaces.ModelColNameEnvironment, nil case interfaces.ModelIdDependencySetting: return interfaces.ModelColNameDependencySetting, nil // invalid default: return res, errors.ErrorModelNotImplemented } } func (b *ColNameBinder) MustBind() (res interface{}) { res, err := b.Bind() if err != nil { panic(err) } return res } func (b *ColNameBinder) BindString() (res string, err error) { res_, err := b.Bind() if err != nil { return "", err } res = res_.(string) return res, nil } func (b *ColNameBinder) MustBindString() (res string) { return b.MustBind().(string) } ================================================ FILE: core/utils/bool.go ================================================ package utils import "github.com/spf13/viper" func EnvIsTrue(key string, defaultOk bool) bool { isTrueBool := viper.GetBool(key) isTrueString := viper.GetString(key) if isTrueString == "" { return defaultOk } return isTrueBool || isTrueString == "Y" } ================================================ FILE: core/utils/bson.go ================================================ package utils import ( "github.com/emirpasic/gods/sets/hashset" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "reflect" ) func BsonMEqual(v1, v2 bson.M) (ok bool) { //ok = reflect.DeepEqual(v1, v2) ok = bsonMEqual(v1, v2) return ok } func bsonMEqual(v1, v2 bson.M) (ok bool) { // all keys allKeys := hashset.New() for key := range v1 { allKeys.Add(key) } for key := range v2 { allKeys.Add(key) } for _, keyRes := range allKeys.Values() { key := keyRes.(string) v1Value, ok := v1[key] if !ok { return false } v2Value, ok := v2[key] if !ok { return false } mode := 0 var v1ValueBsonM bson.M var v1ValueBsonA bson.A switch v1Value.(type) { case bson.M: mode = 1 v1ValueBsonM = v1Value.(bson.M) case bson.A: mode = 2 v1ValueBsonA = v1Value.(bson.A) } var v2ValueBsonM bson.M var v2ValueBsonA bson.A switch v2Value.(type) { case bson.M: if mode != 1 { return false } v2ValueBsonM = v2Value.(bson.M) case bson.A: if mode != 2 { return false } v2ValueBsonA = v2Value.(bson.A) } switch mode { case 0: if v1Value != v2Value { return false } case 1: if !bsonMEqual(v1ValueBsonM, v2ValueBsonM) { return false } case 2: if !reflect.DeepEqual(v1ValueBsonA, v2ValueBsonA) { return false } default: // not reachable return false } } return true } func NormalizeBsonMObjectId(m bson.M) (res bson.M) { for k, v := range m { switch v.(type) { case string: oid, err := primitive.ObjectIDFromHex(v.(string)) if err == nil { m[k] = oid } case bson.M: m[k] = NormalizeBsonMObjectId(v.(bson.M)) } } return m } func DenormalizeBsonMObjectId(m bson.M) (res bson.M) { for k, v := range m { switch v.(type) { case primitive.ObjectID: m[k] = v.(primitive.ObjectID).Hex() case bson.M: m[k] = NormalizeBsonMObjectId(v.(bson.M)) } } return m } func NormalizeObjectId(v interface{}) (res interface{}) { switch v.(type) { case string: oid, err := primitive.ObjectIDFromHex(v.(string)) if err != nil { return v } return oid default: return v } } ================================================ FILE: core/utils/cache.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" mongo2 "go.mongodb.org/mongo-driver/mongo" "time" ) func GetFromDbCache(key string, getFn func() (string, error)) (res string, err error) { col := mongo.GetMongoCol(constants.CacheColName) var d bson.M if err := col.Find(bson.M{ constants.CacheColKey: key, }, nil).One(&d); err != nil { if err != mongo2.ErrNoDocuments { return "", err } // get cache value res, err = getFn() if err != nil { return "", err } // save cache d = bson.M{ constants.CacheColKey: key, constants.CacheColValue: res, constants.CacheColTime: time.Now(), } if _, err := col.Insert(d); err != nil { return "", err } return res, nil } // type conversion r, ok := d[constants.CacheColValue] if !ok { if err := col.Delete(bson.M{constants.CacheColKey: key}); err != nil { return "", err } return GetFromDbCache(key, getFn) } res, ok = r.(string) if !ok { if err := col.Delete(bson.M{constants.CacheColKey: key}); err != nil { return "", err } return GetFromDbCache(key, getFn) } return res, nil } ================================================ FILE: core/utils/chan.go ================================================ 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 } ================================================ FILE: core/utils/chan_test.go ================================================ 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)) }) }) } ================================================ FILE: core/utils/cockroachdb.go ================================================ package utils import ( "context" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/upper/db/v4" "github.com/upper/db/v4/adapter/mssql" "time" ) func GetCockroachdbSession(ds *models.DataSource) (s db.Session, err error) { return getCockroachdbSession(context.Background(), ds) } func GetCockroachdbSessionWithTimeout(ds *models.DataSource, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getCockroachdbSession(ctx, ds) } func getCockroachdbSession(ctx context.Context, ds *models.DataSource) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultCockroachdbPort } // connect settings settings := mssql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mssql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } func GetCockroachdbSessionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getCockroachdbSessionV2(ctx, ds) } func getCockroachdbSessionV2(ctx context.Context, ds *models2.DatabaseV2) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultCockroachdbPort } // connect settings settings := mssql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mssql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } ================================================ FILE: core/utils/cron.go ================================================ package utils import ( "fmt" "math" "strconv" "strings" ) // cronBounds provides a range of acceptable values (plus a map of name to value). type cronBounds struct { min, max uint names map[string]uint } type cronUtils struct { // The cronBounds for each field. seconds cronBounds minutes cronBounds hours cronBounds dom cronBounds months cronBounds dow cronBounds // Set the top bit if a star was included in the expression. starBit uint64 } // getRange returns the bits indicated by the given expression: // number | number "-" number [ "/" number ] // or error parsing range. func (u *cronUtils) getRange(expr string, r cronBounds) (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 = CronUtils.starBit } else { start, err = u.parseIntOrName(lowAndHigh[0], r.names) if err != nil { return 0, err } switch len(lowAndHigh) { case 1: end = start case 2: end, err = u.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 = u.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 u.getBits(start, end, step) | extra, nil } // parseIntOrName returns the (possibly-named) integer contained in expr. func (u *cronUtils) parseIntOrName(expr string, names map[string]uint) (uint, error) { if names != nil { if namedInt, ok := names[strings.ToLower(expr)]; ok { return namedInt, nil } } return u.mustParseInt(expr) } // mustParseInt parses the given expression as an int or returns an error. func (u *cronUtils) 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 (u *cronUtils) 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 cronBounds. (plus the star bit) func (u *cronUtils) all(r cronBounds) uint64 { return u.getBits(r.min, r.max, 1) | CronUtils.starBit } var CronUtils = cronUtils{ // The cronBounds for each field. seconds: cronBounds{0, 59, nil}, minutes: cronBounds{0, 59, nil}, hours: cronBounds{0, 23, nil}, dom: cronBounds{1, 31, nil}, months: cronBounds{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: cronBounds{0, 6, map[string]uint{ "sun": 0, "mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, }}, // Set the top bit if a star was included in the expression. starBit: 1 << 63, } ================================================ FILE: core/utils/debug.go ================================================ package utils import ( "fmt" "github.com/spf13/viper" "time" ) func IsDebug() bool { return viper.GetBool("debug") } func LogDebug(msg string) { if !IsDebug() { return } fmt.Println(fmt.Sprintf("[DEBUG] %s: %s", time.Now().Format("2006-01-02 15:04:05"), msg)) } ================================================ FILE: core/utils/demo.go ================================================ package utils import ( "fmt" "github.com/crawlab-team/crawlab/core/sys_exec" "github.com/crawlab-team/crawlab/db/mongo" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" ) func GetApiAddress() (res string) { apiAddress := viper.GetString("api.address") if apiAddress == "" { return "http://localhost:8000" } return apiAddress } func IsDemo() (ok bool) { return EnvIsTrue("demo", true) } func InitializedDemo() (ok bool) { col := mongo.GetMongoCol("users") n, err := col.Count(nil) if err != nil { return true } return n > 0 } func ImportDemo() (err error) { cmdStr := fmt.Sprintf("crawlab-cli login -a %s && crawlab-demo import", GetApiAddress()) cmd, err := sys_exec.BuildCmd(cmdStr) if err != nil { return err } if err := cmd.Run(); err != nil { trace.PrintError(err) } return nil } func ReimportDemo() (err error) { cmdStr := fmt.Sprintf("crawlab-cli login -a %s && crawlab-demo reimport", GetApiAddress()) cmd, err := sys_exec.BuildCmd(cmdStr) if err != nil { return err } if err := cmd.Run(); err != nil { trace.PrintError(err) } return nil } func CleanupDemo() (err error) { cmdStr := fmt.Sprintf("crawlab-cli login -a %s && crawlab-demo reimport", GetApiAddress()) cmd, err := sys_exec.BuildCmd(cmdStr) if err != nil { return err } if err := cmd.Run(); err != nil { trace.PrintError(err) } return nil } ================================================ FILE: core/utils/di.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "go.uber.org/dig" "os" ) func VisualizeContainer(c *dig.Container) (err error) { if !viper.GetBool("debug.di.visualize") { return nil } if err := dig.Visualize(c, os.Stdout); err != nil { return trace.TraceError(err) } return nil } ================================================ FILE: core/utils/docker.go ================================================ package utils func IsDocker() (ok bool) { return EnvIsTrue("docker", false) } ================================================ FILE: core/utils/encrypt.go ================================================ package utils import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/md5" "crypto/sha256" "encoding/base64" "encoding/hex" "fmt" "github.com/crawlab-team/crawlab/core/constants" "io" ) func GetSecretKey() string { return constants.DefaultEncryptServerKey } func GetSecretKeyBytes() []byte { return []byte(GetSecretKey()) } 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)) } func EncryptMd5(str string) string { w := md5.New() _, _ = io.WriteString(w, str) md5str := fmt.Sprintf("%x", w.Sum(nil)) return md5str } func padding(src []byte, blockSize int) []byte { padNum := blockSize - len(src)%blockSize pad := bytes.Repeat([]byte{byte(padNum)}, padNum) return append(src, pad...) } func unPadding(src []byte) []byte { n := len(src) unPadNum := int(src[n-1]) return src[:n-unPadNum] } func EncryptAES(src string) (res string, err error) { srcBytes := []byte(src) key := GetSecretKeyBytes() block, err := aes.NewCipher(key) if err != nil { return res, err } srcBytes = padding(srcBytes, block.BlockSize()) blockMode := cipher.NewCBCEncrypter(block, key) blockMode.CryptBlocks(srcBytes, srcBytes) res = hex.EncodeToString(srcBytes) return res, nil } func DecryptAES(src string) (res string, err error) { srcBytes, err := hex.DecodeString(src) if err != nil { return res, err } key := GetSecretKeyBytes() block, err := aes.NewCipher(key) if err != nil { return res, err } blockMode := cipher.NewCBCDecrypter(block, key) blockMode.CryptBlocks(srcBytes, srcBytes) res = string(unPadding(srcBytes)) return res, nil } ================================================ FILE: core/utils/encrypt_test.go ================================================ package utils import ( "fmt" "github.com/stretchr/testify/require" "testing" ) func TestEncryptAesPassword(t *testing.T) { plainText := "crawlab" encryptedText, err := EncryptAES(plainText) require.Nil(t, err) decryptedText, err := DecryptAES(encryptedText) require.Nil(t, err) fmt.Println(fmt.Sprintf("plainText: %s", plainText)) fmt.Println(fmt.Sprintf("encryptedText: %s", encryptedText)) fmt.Println(fmt.Sprintf("decryptedText: %s", decryptedText)) require.Equal(t, decryptedText, plainText) require.NotEqual(t, decryptedText, encryptedText) } ================================================ FILE: core/utils/es.go ================================================ package utils import ( "bytes" "context" "encoding/json" "fmt" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/trace" "github.com/elastic/go-elasticsearch/v8" "github.com/elastic/go-elasticsearch/v8/esapi" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) func GetElasticsearchClient(ds *models.DataSource) (c *elasticsearch.Client, err error) { return getElasticsearchClient(context.Background(), ds) } func GetElasticsearchClientWithTimeout(ds *models.DataSource, timeout time.Duration) (c *elasticsearch.Client, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getElasticsearchClient(ctx, ds) } func getElasticsearchClient(ctx context.Context, ds *models.DataSource) (c *elasticsearch.Client, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultElasticsearchPort } // es hosts addresses := []string{ fmt.Sprintf("http://%s:%s", host, port), } // retry backoff rb := backoff.NewExponentialBackOff() // es client options cfg := elasticsearch.Config{ Addresses: addresses, Username: ds.Username, Password: ds.Password, RetryBackoff: func(i int) time.Duration { if i == 1 { rb.Reset() } return rb.NextBackOff() }, } // es client done := make(chan struct{}) go func() { c, err = elasticsearch.NewClient(cfg) if err != nil { return } var res *esapi.Response res, err = c.Info() fmt.Println(res) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return c, err } func GetElasticsearchClientWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (c *elasticsearch.Client, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getElasticsearchClientV2(ctx, ds) } func getElasticsearchClientV2(ctx context.Context, ds *models2.DatabaseV2) (c *elasticsearch.Client, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultElasticsearchPort } // es hosts addresses := []string{ fmt.Sprintf("http://%s:%s", host, port), } // retry backoff rb := backoff.NewExponentialBackOff() // es client options cfg := elasticsearch.Config{ Addresses: addresses, Username: ds.Username, Password: ds.Password, RetryBackoff: func(i int) time.Duration { if i == 1 { rb.Reset() } return rb.NextBackOff() }, } // es client done := make(chan struct{}) go func() { c, err = elasticsearch.NewClient(cfg) if err != nil { return } var res *esapi.Response res, err = c.Info() fmt.Println(res) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return c, err } func GetElasticsearchQuery(query generic.ListQuery) (buf *bytes.Buffer) { q := map[string]interface{}{} if len(query) > 0 { match := getElasticsearchQueryMatch(query) q["query"] = map[string]interface{}{ "match": match, } } buf = &bytes.Buffer{} if err := json.NewEncoder(buf).Encode(q); err != nil { trace.PrintError(err) } return buf } func GetElasticsearchQueryWithOptions(query generic.ListQuery, opts *generic.ListOptions) (buf *bytes.Buffer) { q := map[string]interface{}{ "size": opts.Limit, "from": opts.Skip, // TODO: sort } if len(query) > 0 { match := getElasticsearchQueryMatch(query) q["query"] = map[string]interface{}{ "match": match, } } buf = &bytes.Buffer{} if err := json.NewEncoder(buf).Encode(q); err != nil { trace.PrintError(err) } return buf } func getElasticsearchQueryMatch(query generic.ListQuery) (match map[string]interface{}) { match = map[string]interface{}{} for _, c := range query { switch c.Value.(type) { case primitive.ObjectID: c.Value = c.Value.(primitive.ObjectID).Hex() } switch c.Op { case generic.OpEqual: match[c.Key] = c.Value default: match[c.Key] = map[string]interface{}{ c.Op: c.Value, } } } return match } ================================================ FILE: core/utils/file.go ================================================ package utils import ( "archive/zip" "crypto/md5" "encoding/hex" "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "io" "io/fs" "os" "path" "path/filepath" "runtime/debug" ) 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 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() } // ListDir Add: 增加error类型作为第二返回值 // 在其他函数如 /task/log/file_driver.go中的 *FileLogDriver.cleanup()函数调用时 // 可以通过判断err是否为nil来判断是否有错误发生 func ListDir(path string) ([]fs.FileInfo, error) { list, err := os.ReadDir(path) if err != nil { log.Errorf(err.Error()) debug.PrintStack() return nil, err } var res []fs.FileInfo for _, item := range list { info, err := item.Info() if err != nil { log.Errorf(err.Error()) debug.PrintStack() return nil, err } res = append(res, info) } return res, nil } 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 } // Compress 压缩文件 // 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 TrimFileData(data []byte) (res []byte) { if string(data) == constants.EmptyFileData { return res } return data } func ZipDirectory(dir, zipfile string) error { zipFile, err := os.Create(zipfile) if err != nil { return err } defer zipFile.Close() zipWriter := zip.NewWriter(zipFile) defer zipWriter.Close() baseDir := filepath.Dir(dir) err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } relPath, err := filepath.Rel(baseDir, path) if err != nil { return err } zipFile, err := zipWriter.Create(relPath) if err != nil { return err } file, err := os.Open(path) if err != nil { return err } defer file.Close() _, err = io.Copy(zipFile, file) if err != nil { return err } return nil }) return err } // CopyFile 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()) } // CopyDir Dir copies a whole directory recursively func CopyDir(src string, dst string) error { var err error var fds []os.DirEntry 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 = os.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 GetFileHash(filePath string) (res string, err error) { file, err := os.Open(filePath) if err != nil { return "", err } defer file.Close() hash := md5.New() if _, err := io.Copy(hash, file); err != nil { return "", err } return hex.EncodeToString(hash.Sum(nil)), nil } func ScanDirectory(dir string) (res map[string]entity.FsFileInfo, err error) { files := make(map[string]entity.FsFileInfo) err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } var hash string if !info.IsDir() { hash, err = GetFileHash(path) if err != nil { return err } } relPath, err := filepath.Rel(dir, path) if err != nil { return err } files[relPath] = entity.FsFileInfo{ Name: info.Name(), Path: relPath, FullPath: path, Extension: filepath.Ext(path), IsDir: info.IsDir(), FileSize: info.Size(), ModTime: info.ModTime(), Mode: info.Mode(), Hash: hash, } return nil }) if err != nil { return nil, err } return files, nil } ================================================ FILE: core/utils/file_test.go ================================================ 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") } ================================================ FILE: core/utils/filter.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/errors" "github.com/crawlab-team/crawlab/core/interfaces" "go.mongodb.org/mongo-driver/bson" ) // FilterToQuery Translate entity.Filter to bson.M func FilterToQuery(f interfaces.Filter) (q bson.M, err error) { if f == nil || f.IsNil() { return nil, nil } q = bson.M{} for _, cond := range f.GetConditions() { key := cond.GetKey() op := cond.GetOp() value := cond.GetValue() switch op { case constants.FilterOpNotSet: // do nothing case constants.FilterOpEqual: q[key] = cond.GetValue() case constants.FilterOpNotEqual: q[key] = bson.M{"$ne": value} case constants.FilterOpContains, constants.FilterOpRegex, constants.FilterOpSearch: q[key] = bson.M{"$regex": value, "$options": "i"} case constants.FilterOpNotContains: q[key] = bson.M{"$not": bson.M{"$regex": value}} case constants.FilterOpIn: q[key] = bson.M{"$in": value} case constants.FilterOpNotIn: q[key] = bson.M{"$nin": value} case constants.FilterOpGreaterThan: q[key] = bson.M{"$gt": value} case constants.FilterOpGreaterThanEqual: q[key] = bson.M{"$gte": value} case constants.FilterOpLessThan: q[key] = bson.M{"$lt": value} case constants.FilterOpLessThanEqual: q[key] = bson.M{"$lte": value} default: return nil, errors.ErrorFilterInvalidOperation } } return q, nil } ================================================ FILE: core/utils/git.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/interfaces" vcs "github.com/crawlab-team/crawlab/vcs" ) func InitGitClientAuth(g interfaces.Git, gitClient *vcs.GitClient) { // set auth switch g.GetAuthType() { case constants.GitAuthTypeHttp: gitClient.SetAuthType(vcs.GitAuthTypeHTTP) gitClient.SetUsername(g.GetUsername()) gitClient.SetPassword(g.GetPassword()) case constants.GitAuthTypeSsh: gitClient.SetAuthType(vcs.GitAuthTypeSSH) gitClient.SetUsername(g.GetUsername()) gitClient.SetPrivateKey(g.GetPassword()) } } ================================================ FILE: core/utils/hash.go ================================================ package utils import "encoding/json" func GetObjectHash(obj any) string { data, _ := json.Marshal(obj) if data == nil { // random hash return EncryptMd5(NewUUIDString()) } return EncryptMd5(string(data)) } ================================================ FILE: core/utils/helpers.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/trace" "io" "reflect" "unsafe" ) func BytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } func Close(c io.Closer) { err := c.Close() if err != nil { trace.PrintError(err) } } 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 } ================================================ FILE: core/utils/http.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/entity" "github.com/crawlab-team/crawlab/trace" "github.com/gin-gonic/gin" "net/http" ) func handleError(statusCode int, c *gin.Context, err error, print bool) { if print { trace.PrintError(err) } c.AbortWithStatusJSON(statusCode, entity.Response{ Status: constants.HttpResponseStatusOk, Message: constants.HttpResponseMessageError, Error: err.Error(), }) } func HandleError(statusCode int, c *gin.Context, err error) { handleError(statusCode, c, err, true) } func HandleErrorUnauthorized(c *gin.Context, err error) { HandleError(http.StatusUnauthorized, c, err) } func HandleErrorInternalServerError(c *gin.Context, err error) { HandleError(http.StatusInternalServerError, c, err) } ================================================ FILE: core/utils/init.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/core/interfaces" "sync" ) var moduleInitializedMap = sync.Map{} func InitModule(id interfaces.ModuleId, fn func() error) (err error) { res, ok := moduleInitializedMap.Load(id) if ok { initialized, _ := res.(bool) if initialized { return nil } } if err := fn(); err != nil { return err } moduleInitializedMap.Store(id, true) return nil } func ForceInitModule(fn func() error) (err error) { return fn() } ================================================ FILE: core/utils/json.go ================================================ package utils import "encoding/json" func JsonToBytes(d interface{}) (bytes []byte, err error) { switch d.(type) { case []byte: return d.([]byte), nil default: return json.Marshal(d) } } ================================================ FILE: core/utils/kafka.go ================================================ package utils import ( "context" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/segmentio/kafka-go" "time" ) func GetKafkaConnection(ds *models.DataSource) (c *kafka.Conn, err error) { return getKafkaConnection(context.Background(), ds) } func GetKafkaConnectionWithTimeout(ds *models.DataSource, timeout time.Duration) (c *kafka.Conn, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getKafkaConnection(ctx, ds) } func getKafkaConnection(ctx context.Context, ds *models.DataSource) (c *kafka.Conn, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultKafkaPort } // kafka connection address network := "tcp" address := fmt.Sprintf("%s:%s", host, port) topic := ds.Database partition := 0 // TODO: parameterize // kafka connection return kafka.DialLeader(ctx, network, address, topic, partition) } func GetKafkaConnectionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (c *kafka.Conn, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getKafkaConnectionV2(ctx, ds) } func getKafkaConnectionV2(ctx context.Context, ds *models2.DatabaseV2) (c *kafka.Conn, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultKafkaPort } // kafka connection address network := "tcp" address := fmt.Sprintf("%s:%s", host, port) topic := ds.Database partition := 0 // TODO: parameterize // kafka connection return kafka.DialLeader(ctx, network, address, topic, partition) } ================================================ FILE: core/utils/mongo.go ================================================ package utils import ( "context" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/crawlab-team/crawlab/db/generic" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" mongo2 "go.mongodb.org/mongo-driver/mongo" "time" ) func GetMongoQuery(query generic.ListQuery) (res bson.M) { res = bson.M{} for _, c := range query { switch c.Op { case generic.OpEqual: res[c.Key] = c.Value default: res[c.Key] = bson.M{ c.Op: c.Value, } } } return res } func GetMongoOpts(opts *generic.ListOptions) (res *mongo.FindOptions) { var sort bson.D for _, s := range opts.Sort { direction := 1 if s.Direction == generic.SortDirectionAsc { direction = 1 } else if s.Direction == generic.SortDirectionDesc { direction = -1 } sort = append(sort, bson.E{Key: s.Key, Value: direction}) } return &mongo.FindOptions{ Skip: opts.Skip, Limit: opts.Limit, Sort: sort, } } func GetMongoClient(ds *models.DataSource) (c *mongo2.Client, err error) { return getMongoClient(context.Background(), ds) } func GetMongoClientWithTimeout(ds *models.DataSource, timeout time.Duration) (c *mongo2.Client, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMongoClient(ctx, ds) } func GetMongoClientWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (c *mongo2.Client, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMongoClientV2(ctx, ds) } func getMongoClient(ctx context.Context, ds *models.DataSource) (c *mongo2.Client, err error) { // normalize settings if ds.Host == "" { ds.Host = constants.DefaultHost } if ds.Port == 0 { ds.Port = constants.DefaultMongoPort } // options var opts []mongo.ClientOption opts = append(opts, mongo.WithContext(ctx)) opts = append(opts, mongo.WithUri(ds.Url)) opts = append(opts, mongo.WithHost(ds.Host)) opts = append(opts, mongo.WithPort(ds.Port)) opts = append(opts, mongo.WithDb(ds.Database)) opts = append(opts, mongo.WithUsername(ds.Username)) opts = append(opts, mongo.WithPassword(ds.Password)) // extra if ds.Extra != nil { // auth source authSource, ok := ds.Extra["auth_source"] if ok { opts = append(opts, mongo.WithAuthSource(authSource)) } // auth mechanism authMechanism, ok := ds.Extra["auth_mechanism"] if ok { opts = append(opts, mongo.WithAuthMechanism(authMechanism)) } } // client return mongo.GetMongoClient(opts...) } func getMongoClientV2(ctx context.Context, ds *models2.DatabaseV2) (c *mongo2.Client, err error) { // normalize settings if ds.Host == "" { ds.Host = constants.DefaultHost } if ds.Port == 0 { ds.Port = constants.DefaultMongoPort } // options var opts []mongo.ClientOption opts = append(opts, mongo.WithContext(ctx)) opts = append(opts, mongo.WithUri(ds.URI)) opts = append(opts, mongo.WithHost(ds.Host)) opts = append(opts, mongo.WithPort(ds.Port)) opts = append(opts, mongo.WithDb(ds.Database)) opts = append(opts, mongo.WithUsername(ds.Username)) opts = append(opts, mongo.WithPassword(ds.Password)) // client return mongo.GetMongoClient(opts...) } ================================================ FILE: core/utils/mssql.go ================================================ package utils import ( "context" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/upper/db/v4" "github.com/upper/db/v4/adapter/mssql" "time" ) func GetMssqlSession(ds *models.DataSource) (s db.Session, err error) { return getMssqlSession(context.Background(), ds) } func GetMssqlSessionWithTimeout(ds *models.DataSource, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMssqlSession(ctx, ds) } func getMssqlSession(ctx context.Context, ds *models.DataSource) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultMssqlPort } // connect settings settings := mssql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mssql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } func GetMssqlSessionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMssqlSessionV2(ctx, ds) } func getMssqlSessionV2(ctx context.Context, ds *models2.DatabaseV2) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultMssqlPort } // connect settings settings := mssql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mssql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } ================================================ FILE: core/utils/mysql.go ================================================ package utils import ( "context" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/upper/db/v4" "github.com/upper/db/v4/adapter/mysql" "time" ) func GetMysqlSession(ds *models.DataSource) (s db.Session, err error) { return getMysqlSession(context.Background(), ds) } func GetMysqlSessionWithTimeout(ds *models.DataSource, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMysqlSession(ctx, ds) } func getMysqlSession(ctx context.Context, ds *models.DataSource) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultMysqlPort } // connect settings settings := mysql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mysql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } func GetMysqlSessionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getMysqlSessionV2(ctx, ds) } func getMysqlSessionV2(ctx context.Context, ds *models2.DatabaseV2) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultMysqlPort } // connect settings settings := mysql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = mysql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } ================================================ FILE: core/utils/node.go ================================================ package utils func IsMaster() bool { return EnvIsTrue("node.master", false) } func GetNodeType() string { if IsMaster() { return "master" } else { return "worker" } } ================================================ FILE: core/utils/os.go ================================================ package utils import ( "os" "os/signal" "syscall" ) func DefaultWait() { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit } ================================================ FILE: core/utils/postgresql.go ================================================ package utils import ( "context" "fmt" "github.com/crawlab-team/crawlab/core/constants" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/upper/db/v4" "github.com/upper/db/v4/adapter/postgresql" "time" ) func GetPostgresqlSession(ds *models.DataSource) (s db.Session, err error) { return getPostgresqlSession(context.Background(), ds) } func GetPostgresqlSessionWithTimeout(ds *models.DataSource, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getPostgresqlSession(ctx, ds) } func getPostgresqlSession(ctx context.Context, ds *models.DataSource) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultPostgresqlPort } // connect settings settings := postgresql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = postgresql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } func GetPostgresqlSessionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getPostgresqlSessionV2(ctx, ds) } func getPostgresqlSessionV2(ctx context.Context, ds *models2.DatabaseV2) (s db.Session, err error) { // normalize settings host := ds.Host port := ds.Port if ds.Host == "" { host = constants.DefaultHost } if ds.Port == 0 { port = constants.DefaultPostgresqlPort } // connect settings settings := postgresql.ConnectionURL{ User: ds.Username, Password: ds.Password, Database: ds.Database, Host: fmt.Sprintf("%s:%s", host, port), Options: nil, } // session done := make(chan struct{}) go func() { s, err = postgresql.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } ================================================ FILE: core/utils/result.go ================================================ package utils import ( "encoding/json" "github.com/crawlab-team/crawlab/core/interfaces" ) func GetResultHash(value interface{}, keys []string) (res string, err error) { m := make(map[string]interface{}) for _, k := range keys { _value, ok := value.(interfaces.Result) if !ok { continue } v := _value.GetValue(k) m[k] = v } data, err := json.Marshal(m) if err != nil { return "", err } return EncryptMd5(string(data)), nil } ================================================ FILE: core/utils/rpc.go ================================================ 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] } ================================================ FILE: core/utils/spider.go ================================================ package utils func GetSpiderCol(col string, name string) string { if col == "" { return "results_" + name } return col } ================================================ FILE: core/utils/sql.go ================================================ package utils import ( "github.com/crawlab-team/crawlab/db/generic" "github.com/upper/db/v4" "go.mongodb.org/mongo-driver/bson/primitive" ) func GetSqlQuery(query generic.ListQuery) (res db.Cond) { res = db.Cond{} for _, c := range query { switch c.Value.(type) { case primitive.ObjectID: c.Value = c.Value.(primitive.ObjectID).Hex() } switch c.Op { case generic.OpEqual: res[c.Key] = c.Value default: res[c.Key] = db.Cond{ c.Op: c.Value, } } } // TODO: sort return res } ================================================ FILE: core/utils/sqlite.go ================================================ package utils import ( "context" "github.com/crawlab-team/crawlab/core/models/models" models2 "github.com/crawlab-team/crawlab/core/models/models/v2" "github.com/upper/db/v4" "github.com/upper/db/v4/adapter/sqlite" "time" ) func GetSqliteSession(ds *models.DataSource) (s db.Session, err error) { return getSqliteSession(context.Background(), ds) } func GetSqliteSessionWithTimeout(ds *models.DataSource, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getSqliteSession(ctx, ds) } func getSqliteSession(ctx context.Context, ds *models.DataSource) (s db.Session, err error) { // connect settings settings := sqlite.ConnectionURL{ Database: ds.Database, Options: nil, } // session done := make(chan struct{}) go func() { s, err = sqlite.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } func GetSqliteSessionWithTimeoutV2(ds *models2.DatabaseV2, timeout time.Duration) (s db.Session, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return getSqliteSessionV2(ctx, ds) } func getSqliteSessionV2(ctx context.Context, ds *models2.DatabaseV2) (s db.Session, err error) { // connect settings settings := sqlite.ConnectionURL{ Database: ds.Database, Options: nil, } // session done := make(chan struct{}) go func() { s, err = sqlite.Open(settings) close(done) }() // wait for done select { case <-ctx.Done(): if ctx.Err() != nil { err = ctx.Err() } case <-done: } return s, err } ================================================ FILE: core/utils/stats.go ================================================ package utils ================================================ FILE: core/utils/system.go ================================================ package utils import "github.com/spf13/viper" func IsPro() bool { return viper.GetString("edition") == "global.edition.pro" } ================================================ FILE: core/utils/task.go ================================================ package utils import "github.com/crawlab-team/crawlab/core/constants" func IsCancellable(status string) bool { switch status { case constants.TaskStatusPending, constants.TaskStatusRunning: return true default: return false } } ================================================ FILE: core/utils/time.go ================================================ package utils import ( "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/trace" "regexp" "strconv" "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) } func GetTimeUnitParts(timeUnit string) (num int, unit string, err error) { re := regexp.MustCompile(`^(\d+)([a-zA-Z])$`) groups := re.FindStringSubmatch(timeUnit) if len(groups) < 3 { err = errors.New("failed to parse duration text") log.Errorf("failed to parse duration text: %v", err) trace.PrintError(err) return 0, "", err } num, err = strconv.Atoi(groups[1]) if err != nil { log.Errorf("failed to convert string to int: %v", err) trace.PrintError(err) return 0, "", err } unit = groups[2] return num, unit, nil } func GetTimeDuration(num string, unit string) (d time.Duration, err error) { numInt, err := strconv.Atoi(num) if err != nil { log.Errorf("failed to convert string to int: %v", err) trace.PrintError(err) return d, err } switch unit { case "s": d = time.Duration(numInt) * time.Second case "m": d = time.Duration(numInt) * time.Minute case "h": d = time.Duration(numInt) * time.Hour case "d": d = time.Duration(numInt) * 24 * time.Hour case "w": d = time.Duration(numInt) * 7 * 24 * time.Hour case "M": d = time.Duration(numInt) * 30 * 24 * time.Hour case "y": d = time.Duration(numInt) * 365 * 24 * time.Hour default: err = errors.New("invalid time unit") log.Errorf("invalid time unit: %v", unit) trace.PrintError(err) return d, err } return d, nil } ================================================ FILE: core/utils/uuid.go ================================================ package utils import "github.com/google/uuid" func NewUUIDString() (res string) { id, _ := uuid.NewUUID() return id.String() } ================================================ FILE: db/.editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true ================================================ FILE: db/.gitignore ================================================ .idea .DS_Store tmp/ vendor/ go.sum ================================================ FILE: db/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2020, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: db/README.md ================================================ # crawlab-db Backend database module for Crawlab ================================================ FILE: db/errors/base.go ================================================ package errors const ( errorPrefixMongo = "mongo" errorPrefixRedis = "redis" ) ================================================ FILE: db/errors/errors.go ================================================ package errors import "errors" var ( ErrInvalidType = errors.New("invalid type") ErrMissingValue = errors.New("missing value") ErrNoCursor = errors.New("no cursor") ErrAlreadyLocked = errors.New("already locked") ) ================================================ FILE: db/errors/redis.go ================================================ package errors import ( "errors" "fmt" ) var ( ErrorRedisInvalidType = NewRedisError("invalid type") ErrorRedisLocked = NewRedisError("locked") ) func NewRedisError(msg string) (err error) { return errors.New(fmt.Sprintf("%s: %s", errorPrefixRedis, msg)) } ================================================ FILE: db/generic/base.go ================================================ package generic const ( DataSourceTypeMongo = "mongo" DataSourceTypeMysql = "mysql" DataSourceTypePostgres = "postgres" DataSourceTypeElasticSearch = "postgres" ) ================================================ FILE: db/generic/list.go ================================================ package generic type ListQueryCondition struct { Key string Op string Value interface{} } type ListQuery []ListQueryCondition type ListOptions struct { Skip int Limit int Sort []ListSort } ================================================ FILE: db/generic/op.go ================================================ package generic type Op string const ( OpEqual = "eq" ) ================================================ FILE: db/generic/sort.go ================================================ package generic type SortDirection string const ( SortDirectionAsc SortDirection = "asc" SortDirectionDesc SortDirection = "desc" ) type ListSort struct { Key string Direction SortDirection } ================================================ FILE: db/go.mod ================================================ module github.com/crawlab-team/crawlab/db go 1.22 replace github.com/crawlab-team/crawlab/trace => ../trace require ( github.com/apex/log v1.9.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/crawlab-team/crawlab/trace v0.0.0-20240614095218-7b4ee8399ab0 github.com/gomodule/redigo v2.0.0+incompatible github.com/jmoiron/sqlx v1.2.0 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.1 ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/lib/pq v1.10.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/ztrue/tracerr v0.4.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: db/interfaces.go ================================================ package db import "time" type RedisClient interface { Ping() (err error) Keys(pattern string) (values []string, err error) AllKeys() (values []string, err error) Get(collection string) (value string, err error) Set(collection string, value string) (err error) Del(collection string) (err error) RPush(collection string, value interface{}) (err error) LPush(collection string, value interface{}) (err error) LPop(collection string) (value string, err error) RPop(collection string) (value string, err error) LLen(collection string) (count int, err error) BRPop(collection string, timeout int) (value string, err error) BLPop(collection string, timeout int) (value string, err error) HSet(collection string, key string, value string) (err error) HGet(collection string, key string) (value string, err error) HDel(collection string, key string) (err error) HScan(collection string) (results map[string]string, err error) HKeys(collection string) (results []string, err error) ZAdd(collection string, score float32, value interface{}) (err error) ZCount(collection string, min string, max string) (count int, err error) ZCountAll(collection string) (count int, err error) ZScan(collection string, pattern string, count int) (results []string, err error) ZPopMax(collection string, count int) (results []string, err error) ZPopMin(collection string, count int) (results []string, err error) ZPopMaxOne(collection string) (value string, err error) ZPopMinOne(collection string) (value string, err error) BZPopMax(collection string, timeout int) (value string, err error) BZPopMin(collection string, timeout int) (value string, err error) Lock(lockKey string) (value int64, err error) UnLock(lockKey string, value int64) MemoryStats() (stats map[string]int64, err error) SetBackoffMaxInterval(interval time.Duration) SetTimeout(timeout int) } ================================================ FILE: db/mongo/client.go ================================================ package mongo import ( "context" "encoding/json" "fmt" "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "sync" ) var AppName = "crawlab-db" var _clientMap = map[string]*mongo.Client{} var _mu sync.Mutex func GetMongoClient(opts ...ClientOption) (c *mongo.Client, err error) { // client options _opts := &ClientOptions{} for _, op := range opts { op(_opts) } if _opts.Uri == "" { _opts.Uri = viper.GetString("mongo.uri") } if _opts.Host == "" { _opts.Host = viper.GetString("mongo.host") if _opts.Host == "" { _opts.Host = "localhost" } } if _opts.Port == 0 { _opts.Port = viper.GetInt("mongo.port") if _opts.Port == 0 { _opts.Port = 27017 } } if _opts.Db == "" { _opts.Db = viper.GetString("mongo.db") if _opts.Db == "" { _opts.Db = "admin" } } if len(_opts.Hosts) == 0 { _opts.Hosts = viper.GetStringSlice("mongo.hosts") } if _opts.Username == "" { _opts.Username = viper.GetString("mongo.username") } if _opts.Password == "" { _opts.Password = viper.GetString("mongo.password") } if _opts.AuthSource == "" { _opts.AuthSource = viper.GetString("mongo.authSource") if _opts.AuthSource == "" { _opts.AuthSource = "admin" } } if _opts.AuthMechanism == "" { _opts.AuthMechanism = viper.GetString("mongo.authMechanism") } if _opts.AuthMechanismProperties == nil { _opts.AuthMechanismProperties = viper.GetStringMapString("mongo.authMechanismProperties") } // client options key json string _optsKeyBytes, err := json.Marshal(_opts) if err != nil { return nil, trace.TraceError(err) } _optsKey := string(_optsKeyBytes) // attempt to get client by client options c, ok := _clientMap[_optsKey] if ok { return c, nil } // create new mongo client c, err = newMongoClient(_opts.Context, _opts) if err != nil { return nil, err } // add to map _mu.Lock() _clientMap[_optsKey] = c _mu.Unlock() return c, nil } func newMongoClient(ctx context.Context, _opts *ClientOptions) (c *mongo.Client, err error) { // mongo client options mongoOpts := &options.ClientOptions{ AppName: &AppName, } if _opts.Uri != "" { // uri is set mongoOpts.ApplyURI(_opts.Uri) } else { // uri is unset // username and password are set if _opts.Username != "" && _opts.Password != "" { mongoOpts.SetAuth(options.Credential{ AuthMechanism: _opts.AuthMechanism, AuthMechanismProperties: _opts.AuthMechanismProperties, AuthSource: _opts.AuthSource, Username: _opts.Username, Password: _opts.Password, PasswordSet: true, }) } if len(_opts.Hosts) > 0 { // hosts are set mongoOpts.SetHosts(_opts.Hosts) } else { // hosts are unset mongoOpts.ApplyURI(fmt.Sprintf("mongodb://%s:%d/%s", _opts.Host, _opts.Port, _opts.Db)) } } // attempt to connect with retry bp := backoff.NewExponentialBackOff() err = backoff.Retry(func() error { errMsg := fmt.Sprintf("waiting for connect mongo database, after %f seconds try again.", bp.NextBackOff().Seconds()) c, err = mongo.NewClient(mongoOpts) if err != nil { log.WithError(err).Warnf(errMsg) return err } if err := c.Connect(ctx); err != nil { log.WithError(err).Warnf(errMsg) return err } return nil }, bp) return c, nil } ================================================ FILE: db/mongo/client_options.go ================================================ package mongo import "context" type ClientOption func(options *ClientOptions) type ClientOptions struct { Context context.Context Uri string Host string Port int Db string Hosts []string Username string Password string AuthSource string AuthMechanism string AuthMechanismProperties map[string]string } func WithContext(ctx context.Context) ClientOption { return func(options *ClientOptions) { options.Context = ctx } } func WithUri(value string) ClientOption { return func(options *ClientOptions) { options.Uri = value } } func WithHost(value string) ClientOption { return func(options *ClientOptions) { options.Host = value } } func WithPort(value int) ClientOption { return func(options *ClientOptions) { options.Port = value } } func WithDb(value string) ClientOption { return func(options *ClientOptions) { options.Db = value } } func WithHosts(value []string) ClientOption { return func(options *ClientOptions) { options.Hosts = value } } func WithUsername(value string) ClientOption { return func(options *ClientOptions) { options.Username = value } } func WithPassword(value string) ClientOption { return func(options *ClientOptions) { options.Password = value } } func WithAuthSource(value string) ClientOption { return func(options *ClientOptions) { options.AuthSource = value } } func WithAuthMechanism(value string) ClientOption { return func(options *ClientOptions) { options.AuthMechanism = value } } ================================================ FILE: db/mongo/client_test.go ================================================ package mongo import ( "github.com/stretchr/testify/require" "testing" ) func setupMongoTest() (err error) { return nil } func cleanupMongoTest() { } func TestMongoInitMongo(t *testing.T) { err := setupMongoTest() require.Nil(t, err) _, err = GetMongoClient() require.Nil(t, err) cleanupMongoTest() } ================================================ FILE: db/mongo/col.go ================================================ package mongo import ( "context" "github.com/crawlab-team/crawlab/db/errors" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type ColInterface interface { Insert(doc interface{}) (id primitive.ObjectID, err error) InsertMany(docs []interface{}) (ids []primitive.ObjectID, err error) UpdateId(id primitive.ObjectID, update interface{}) (err error) Update(query bson.M, update interface{}) (err error) UpdateWithOptions(query bson.M, update interface{}, opts *options.UpdateOptions) (err error) ReplaceId(id primitive.ObjectID, doc interface{}) (err error) Replace(query bson.M, doc interface{}) (err error) ReplaceWithOptions(query bson.M, doc interface{}, opts *options.ReplaceOptions) (err error) DeleteId(id primitive.ObjectID) (err error) Delete(query bson.M) (err error) DeleteWithOptions(query bson.M, opts *options.DeleteOptions) (err error) Find(query bson.M, opts *FindOptions) (fr *FindResult) FindId(id primitive.ObjectID) (fr *FindResult) Count(query bson.M) (total int, err error) Aggregate(pipeline mongo.Pipeline, opts *options.AggregateOptions) (fr *FindResult) CreateIndex(indexModel mongo.IndexModel) (err error) CreateIndexes(indexModels []mongo.IndexModel) (err error) MustCreateIndex(indexModel mongo.IndexModel) MustCreateIndexes(indexModels []mongo.IndexModel) DeleteIndex(name string) (err error) DeleteAllIndexes() (err error) ListIndexes() (indexes []map[string]interface{}, err error) GetContext() (ctx context.Context) GetName() (name string) GetCollection() (c *mongo.Collection) } type FindOptions struct { Skip int Limit int Sort bson.D } type Col struct { ctx context.Context db *mongo.Database c *mongo.Collection } func (col *Col) Insert(doc interface{}) (id primitive.ObjectID, err error) { res, err := col.c.InsertOne(col.ctx, doc) if err != nil { return primitive.NilObjectID, trace.TraceError(err) } if id, ok := res.InsertedID.(primitive.ObjectID); ok { return id, nil } return primitive.NilObjectID, trace.TraceError(errors.ErrInvalidType) } func (col *Col) InsertMany(docs []interface{}) (ids []primitive.ObjectID, err error) { res, err := col.c.InsertMany(col.ctx, docs) if err != nil { return nil, trace.TraceError(err) } for _, v := range res.InsertedIDs { switch v.(type) { case primitive.ObjectID: id := v.(primitive.ObjectID) ids = append(ids, id) default: return nil, trace.TraceError(errors.ErrInvalidType) } } return ids, nil } func (col *Col) UpdateId(id primitive.ObjectID, update interface{}) (err error) { _, err = col.c.UpdateOne(col.ctx, bson.M{"_id": id}, update) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) Update(query bson.M, update interface{}) (err error) { return col.UpdateWithOptions(query, update, nil) } func (col *Col) UpdateWithOptions(query bson.M, update interface{}, opts *options.UpdateOptions) (err error) { if opts == nil { _, err = col.c.UpdateMany(col.ctx, query, update) } else { _, err = col.c.UpdateMany(col.ctx, query, update, opts) } if err != nil { return trace.TraceError(err) } return nil } func (col *Col) ReplaceId(id primitive.ObjectID, doc interface{}) (err error) { return col.Replace(bson.M{"_id": id}, doc) } func (col *Col) Replace(query bson.M, doc interface{}) (err error) { return col.ReplaceWithOptions(query, doc, nil) } func (col *Col) ReplaceWithOptions(query bson.M, doc interface{}, opts *options.ReplaceOptions) (err error) { if opts == nil { _, err = col.c.ReplaceOne(col.ctx, query, doc) } else { _, err = col.c.ReplaceOne(col.ctx, query, doc, opts) } if err != nil { return trace.TraceError(err) } return nil } func (col *Col) DeleteId(id primitive.ObjectID) (err error) { _, err = col.c.DeleteOne(col.ctx, bson.M{"_id": id}) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) Delete(query bson.M) (err error) { return col.DeleteWithOptions(query, nil) } func (col *Col) DeleteWithOptions(query bson.M, opts *options.DeleteOptions) (err error) { if opts == nil { _, err = col.c.DeleteMany(col.ctx, query) } else { _, err = col.c.DeleteMany(col.ctx, query, opts) } if err != nil { return trace.TraceError(err) } return nil } func (col *Col) Find(query bson.M, opts *FindOptions) (fr *FindResult) { _opts := &options.FindOptions{} if opts != nil { if opts.Skip != 0 { skipInt64 := int64(opts.Skip) _opts.Skip = &skipInt64 } if opts.Limit != 0 { limitInt64 := int64(opts.Limit) _opts.Limit = &limitInt64 } if opts.Sort != nil { _opts.Sort = opts.Sort } } cur, err := col.c.Find(col.ctx, query, _opts) if err != nil { return &FindResult{ col: col, err: err, } } fr = &FindResult{ col: col, cur: cur, } return fr } func (col *Col) FindId(id primitive.ObjectID) (fr *FindResult) { res := col.c.FindOne(col.ctx, bson.M{"_id": id}) if res.Err() != nil { return &FindResult{ col: col, err: res.Err(), } } fr = &FindResult{ col: col, res: res, } return fr } func (col *Col) Count(query bson.M) (total int, err error) { totalInt64, err := col.c.CountDocuments(col.ctx, query) if err != nil { return 0, err } total = int(totalInt64) return total, nil } func (col *Col) Aggregate(pipeline mongo.Pipeline, opts *options.AggregateOptions) (fr *FindResult) { cur, err := col.c.Aggregate(col.ctx, pipeline, opts) if err != nil { return &FindResult{ col: col, err: err, } } if cur.Err() != nil { return &FindResult{ col: col, err: cur.Err(), } } fr = &FindResult{ col: col, cur: cur, } return fr } func (col *Col) CreateIndex(indexModel mongo.IndexModel) (err error) { _, err = col.c.Indexes().CreateOne(col.ctx, indexModel) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) CreateIndexes(indexModels []mongo.IndexModel) (err error) { _, err = col.c.Indexes().CreateMany(col.ctx, indexModels) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) MustCreateIndex(indexModel mongo.IndexModel) { _, _ = col.c.Indexes().CreateOne(col.ctx, indexModel) } func (col *Col) MustCreateIndexes(indexModels []mongo.IndexModel) { _, _ = col.c.Indexes().CreateMany(col.ctx, indexModels) } func (col *Col) DeleteIndex(name string) (err error) { _, err = col.c.Indexes().DropOne(col.ctx, name) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) DeleteAllIndexes() (err error) { _, err = col.c.Indexes().DropAll(col.ctx) if err != nil { return trace.TraceError(err) } return nil } func (col *Col) ListIndexes() (indexes []map[string]interface{}, err error) { cur, err := col.c.Indexes().List(col.ctx) if err != nil { return nil, err } if err := cur.All(col.ctx, &indexes); err != nil { return nil, err } return indexes, nil } func (col *Col) GetContext() (ctx context.Context) { return col.ctx } func (col *Col) GetName() (name string) { return col.c.Name() } func (col *Col) GetCollection() (c *mongo.Collection) { return col.c } func GetMongoCol(colName string) (col *Col) { return GetMongoColWithDb(colName, nil) } func GetMongoColWithDb(colName string, db *mongo.Database) (col *Col) { ctx := context.Background() if db == nil { db = GetMongoDb("") } c := db.Collection(colName) col = &Col{ ctx: ctx, db: db, c: c, } return col } ================================================ FILE: db/mongo/col_test.go ================================================ package mongo import ( "fmt" "github.com/spf13/viper" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "strconv" "testing" ) type ColTestObject struct { dbName string colName string col *Col } type TestDocument struct { Key string `bson:"key"` Value int `bson:"value"` Tags []string `bson:"tags"` } type TestAggregateResult struct { Id string `bson:"_id"` Count int `bson:"count"` Value int `bson:"value"` } func setupColTest() (to *ColTestObject, err error) { dbName := "test_db" colName := "test_col" viper.Set("mongo.db", dbName) col := GetMongoCol(colName) if err := col.db.Drop(col.ctx); err != nil { return nil, err } return &ColTestObject{ dbName: dbName, colName: colName, col: col, }, nil } func cleanupColTest(to *ColTestObject) { _ = to.col.db.Drop(to.col.ctx) } func TestGetMongoCol(t *testing.T) { colName := "test_col" col := GetMongoCol(colName) require.Equal(t, colName, col.c.Name()) } func TestGetMongoColWithDb(t *testing.T) { dbName := "test_db" colName := "test_col" col := GetMongoColWithDb(colName, dbName) require.Equal(t, colName, col.c.Name()) require.Equal(t, dbName, col.db.Name()) } func TestCol_Insert(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "value"}) require.Nil(t, err) require.IsType(t, primitive.ObjectID{}, id) var doc map[string]string err = to.col.FindId(id).One(&doc) require.Nil(t, err) require.Equal(t, doc["key"], "value") cleanupColTest(to) } func TestCol_InsertMany(t *testing.T) { to, err := setupColTest() require.Nil(t, err) n := 10 var docs []interface{} for i := 0; i < n; i++ { docs = append(docs, bson.M{"key": fmt.Sprintf("value-%d", i)}) } ids, err := to.col.InsertMany(docs) require.Nil(t, err) require.Equal(t, n, len(ids)) var resDocs []map[string]string err = to.col.Find(nil, &FindOptions{Sort: bson.D{{"_id", 1}}}).All(&resDocs) require.Nil(t, err) require.Equal(t, n, len(resDocs)) for i, doc := range resDocs { require.Equal(t, fmt.Sprintf("value-%d", i), doc["key"]) } cleanupColTest(to) } func TestCol_UpdateId(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "old-value"}) require.Nil(t, err) err = to.col.UpdateId(id, bson.M{ "$set": bson.M{ "key": "new-value", }, }) require.Nil(t, err) var doc map[string]string err = to.col.FindId(id).One(&doc) require.Nil(t, err) require.Equal(t, "new-value", doc["key"]) cleanupColTest(to) } func TestCol_Update(t *testing.T) { to, err := setupColTest() require.Nil(t, err) n := 10 var docs []interface{} for i := 0; i < n; i++ { docs = append(docs, bson.M{"key": fmt.Sprintf("old-value-%d", i)}) } err = to.col.Update(nil, bson.M{ "$set": bson.M{ "key": "new-value", }, }) require.Nil(t, err) var resDocs []map[string]string err = to.col.Find(nil, &FindOptions{Sort: bson.D{{"_id", 1}}}).All(&resDocs) require.Nil(t, err) for _, doc := range resDocs { require.Equal(t, "new-value", doc["key"]) } cleanupColTest(to) } func TestCol_ReplaceId(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "old-value"}) require.Nil(t, err) var doc map[string]interface{} err = to.col.FindId(id).One(&doc) require.Nil(t, err) doc["key"] = "new-value" err = to.col.ReplaceId(id, doc) require.Nil(t, err) err = to.col.FindId(id).One(doc) require.Nil(t, err) require.Equal(t, "new-value", doc["key"]) cleanupColTest(to) } func TestCol_Replace(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "old-value"}) require.Nil(t, err) var doc map[string]interface{} err = to.col.FindId(id).One(&doc) require.Nil(t, err) doc["key"] = "new-value" err = to.col.Replace(bson.M{"key": "old-value"}, doc) require.Nil(t, err) err = to.col.FindId(id).One(&doc) require.Nil(t, err) require.Equal(t, "new-value", doc["key"]) cleanupColTest(to) } func TestCol_DeleteId(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "value"}) require.Nil(t, err) err = to.col.DeleteId(id) require.Nil(t, err) total, err := to.col.Count(nil) require.Nil(t, err) require.Equal(t, 0, total) cleanupColTest(to) } func TestCol_Delete(t *testing.T) { to, err := setupColTest() require.Nil(t, err) n := 10 var docs []interface{} for i := 0; i < n; i++ { docs = append(docs, bson.M{"key": fmt.Sprintf("value-%d", i)}) } ids, err := to.col.InsertMany(docs) require.Nil(t, err) require.Equal(t, n, len(ids)) err = to.col.Delete(bson.M{"key": "value-0"}) require.Nil(t, err) total, err := to.col.Count(nil) require.Nil(t, err) require.Equal(t, n-1, total) err = to.col.Delete(nil) require.Nil(t, err) total, err = to.col.Count(nil) require.Nil(t, err) require.Equal(t, 0, total) cleanupColTest(to) } func TestCol_FindId(t *testing.T) { to, err := setupColTest() require.Nil(t, err) id, err := to.col.Insert(bson.M{"key": "value"}) require.Nil(t, err) var doc map[string]string err = to.col.FindId(id).One(&doc) require.Nil(t, err) require.Equal(t, "value", doc["key"]) cleanupColTest(to) } func TestCol_Find(t *testing.T) { to, err := setupColTest() require.Nil(t, err) n := 10 var docs []interface{} for i := 0; i < n; i++ { docs = append(docs, TestDocument{ Key: fmt.Sprintf("value-%d", i), Tags: []string{"test tag"}, }) } ids, err := to.col.InsertMany(docs) require.Nil(t, err) require.Equal(t, n, len(ids)) err = to.col.Find(nil, nil).All(&docs) require.Nil(t, err) require.Equal(t, n, len(docs)) err = to.col.Find(bson.M{"key": bson.M{"$gte": fmt.Sprintf("value-%d", 5)}}, nil).All(&docs) require.Nil(t, err) require.Equal(t, n-5, len(docs)) err = to.col.Find(nil, &FindOptions{ Skip: 5, }).All(&docs) require.Nil(t, err) require.Equal(t, n-5, len(docs)) err = to.col.Find(nil, &FindOptions{ Limit: 5, }).All(&docs) require.Nil(t, err) require.Equal(t, 5, len(docs)) var resDocs []TestDocument err = to.col.Find(nil, &FindOptions{ Sort: bson.D{{"key", 1}}, }).All(&resDocs) require.Nil(t, err) require.Greater(t, len(resDocs), 0) require.Equal(t, "value-0", resDocs[0].Key) err = to.col.Find(nil, &FindOptions{ Sort: bson.D{{"key", -1}}, }).All(&resDocs) require.Nil(t, err) require.Greater(t, len(resDocs), 0) require.Equal(t, fmt.Sprintf("value-%d", n-1), resDocs[0].Key) var resDocs2 []TestDocument err = to.col.Find(bson.M{"tags": bson.M{"$in": []string{"test tag"}}}, nil).All(&resDocs2) require.Nil(t, err) require.Greater(t, len(resDocs2), 0) cleanupColTest(to) } func TestCol_CreateIndex(t *testing.T) { to, err := setupColTest() require.Nil(t, err) err = to.col.CreateIndex(mongo.IndexModel{ Keys: bson.D{{"key", 1}}, }) require.Nil(t, err) indexes, err := to.col.ListIndexes() require.Nil(t, err) require.Equal(t, 2, len(indexes)) cleanupColTest(to) } func TestCol_Aggregate(t *testing.T) { to, err := setupColTest() require.Nil(t, err) n := 10 v := 2 var docs []interface{} for i := 0; i < n; i++ { docs = append(docs, TestDocument{ Key: fmt.Sprintf("%d", i%2), Value: v, }) } ids, err := to.col.InsertMany(docs) require.Nil(t, err) require.Equal(t, n, len(ids)) pipeline := mongo.Pipeline{ { { "$group", bson.D{ {"_id", "$key"}, { "count", bson.D{{"$sum", 1}}, }, { "value", bson.D{{"$sum", "$value"}}, }, }, }, }, { { "$sort", bson.D{{"_id", 1}}, }, }, } var results []TestAggregateResult err = to.col.Aggregate(pipeline, nil).All(&results) require.Nil(t, err) require.Equal(t, 2, len(results)) for i, r := range results { require.Equal(t, strconv.Itoa(i), r.Id) require.Equal(t, n/2, r.Count) require.Equal(t, n*v/2, r.Value) } } func TestCol_CreateIndexes(t *testing.T) { to, err := setupColTest() require.Nil(t, err) err = to.col.CreateIndexes([]mongo.IndexModel{ { Keys: bson.D{{"key", 1}}, }, { Keys: bson.D{{"empty-key", 1}}, }, }) require.Nil(t, err) indexes, err := to.col.ListIndexes() require.Nil(t, err) require.Equal(t, 3, len(indexes)) cleanupColTest(to) } func TestCol_DeleteIndex(t *testing.T) { to, err := setupColTest() require.Nil(t, err) err = to.col.CreateIndex(mongo.IndexModel{ Keys: bson.D{{"key", 1}}, }) require.Nil(t, err) indexes, err := to.col.ListIndexes() require.Nil(t, err) require.Equal(t, 2, len(indexes)) for _, index := range indexes { name, ok := index["name"].(string) require.True(t, ok) if name != "_id_" { err = to.col.DeleteIndex(name) require.Nil(t, err) break } } indexes, err = to.col.ListIndexes() require.Nil(t, err) require.Equal(t, 1, len(indexes)) cleanupColTest(to) } func TestCol_DeleteIndexes(t *testing.T) { to, err := setupColTest() require.Nil(t, err) err = to.col.CreateIndexes([]mongo.IndexModel{ { Keys: bson.D{{"key", 1}}, }, { Keys: bson.D{{"empty-key", 1}}, }, }) require.Nil(t, err) err = to.col.DeleteAllIndexes() require.Nil(t, err) indexes, err := to.col.ListIndexes() require.Nil(t, err) require.Equal(t, 1, len(indexes)) cleanupColTest(to) } ================================================ FILE: db/mongo/db.go ================================================ package mongo import ( "github.com/crawlab-team/crawlab/trace" "github.com/spf13/viper" "go.mongodb.org/mongo-driver/mongo" ) func GetMongoDb(dbName string, opts ...DbOption) (db *mongo.Database) { if dbName == "" { dbName = viper.GetString("mongo.db") } if dbName == "" { dbName = "test" } _opts := &DbOptions{} for _, op := range opts { op(_opts) } var c *mongo.Client if _opts.client == nil { var err error c, err = GetMongoClient() if err != nil { trace.PrintError(err) return nil } } else { c = _opts.client } return c.Database(dbName, nil) } ================================================ FILE: db/mongo/db_options.go ================================================ package mongo import "go.mongodb.org/mongo-driver/mongo" type DbOption func(options *DbOptions) type DbOptions struct { client *mongo.Client } func WithDbClient(c *mongo.Client) DbOption { return func(options *DbOptions) { options.client = c } } ================================================ FILE: db/mongo/db_test.go ================================================ package mongo import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" "testing" ) func TestMongoGetDb(t *testing.T) { dbName := "test_db" viper.Set("mongo.db", dbName) err := InitMongo() require.Nil(t, err) db := GetMongoDb("") require.Equal(t, dbName, db.Name()) } ================================================ FILE: db/mongo/result.go ================================================ package mongo import ( "context" "github.com/crawlab-team/crawlab/db/errors" "go.mongodb.org/mongo-driver/mongo" ) type FindResultInterface interface { One(val interface{}) (err error) All(val interface{}) (err error) GetCol() (col *Col) GetSingleResult() (res *mongo.SingleResult) GetCursor() (cur *mongo.Cursor) GetError() (err error) } func NewFindResult() (fr *FindResult) { return &FindResult{} } func NewFindResultWithError(err error) (fr *FindResult) { return &FindResult{ err: err, } } type FindResult struct { col *Col res *mongo.SingleResult cur *mongo.Cursor err error } func (fr *FindResult) GetError() (err error) { //TODO implement me panic("implement me") } func (fr *FindResult) One(val interface{}) (err error) { if fr.err != nil { return fr.err } if fr.cur != nil { if !fr.cur.TryNext(fr.col.ctx) { return mongo.ErrNoDocuments } return fr.cur.Decode(val) } return fr.res.Decode(val) } func (fr *FindResult) All(val interface{}) (err error) { if fr.err != nil { return fr.err } var ctx context.Context if fr.col == nil { ctx = context.Background() } else { ctx = fr.col.ctx } if fr.cur == nil { return errors.ErrNoCursor } if !fr.cur.TryNext(ctx) { return ctx.Err() } return fr.cur.All(ctx, val) } func (fr *FindResult) GetCol() (col *Col) { return fr.col } func (fr *FindResult) GetSingleResult() (res *mongo.SingleResult) { return fr.res } func (fr *FindResult) GetCursor() (cur *mongo.Cursor) { return fr.cur } ================================================ FILE: db/mongo/transaction.go ================================================ package mongo import ( "context" "github.com/crawlab-team/crawlab/trace" "go.mongodb.org/mongo-driver/mongo" ) func RunTransaction(fn func(mongo.SessionContext) error) (err error) { return RunTransactionWithContext(context.Background(), fn) } func RunTransactionWithContext(ctx context.Context, fn func(mongo.SessionContext) error) (err error) { // default client c, err := GetMongoClient() if err != nil { return err } // start session s, err := c.StartSession() if err != nil { return trace.TraceError(err) } // start transaction if err := s.StartTransaction(); err != nil { return trace.TraceError(err) } // perform operation if err := mongo.WithSession(ctx, s, func(sc mongo.SessionContext) error { if err := fn(sc); err != nil { return trace.TraceError(err) } if err = s.CommitTransaction(sc); err != nil { return trace.TraceError(err) } return nil }); err != nil { return trace.TraceError(err) } return nil } ================================================ FILE: db/redis/client.go ================================================ package redis import ( "github.com/apex/log" "github.com/crawlab-team/crawlab/db" "github.com/crawlab-team/crawlab/db/errors" "github.com/crawlab-team/crawlab/db/utils" "github.com/crawlab-team/crawlab/trace" "github.com/gomodule/redigo/redis" "reflect" "strings" "time" ) type Client struct { // settings backoffMaxInterval time.Duration timeout int // internals pool *redis.Pool } func (client *Client) Ping() error { c := client.pool.Get() defer utils.Close(c) if _, err := redis.String(c.Do("PING")); err != nil { if err != redis.ErrNil { return trace.TraceError(err) } return err } return nil } func (client *Client) Keys(pattern string) (values []string, err error) { c := client.pool.Get() defer utils.Close(c) values, err = redis.Strings(c.Do("KEYS", pattern)) if err != nil { return nil, trace.TraceError(err) } return values, nil } func (client *Client) AllKeys() (values []string, err error) { return client.Keys("*") } func (client *Client) Get(collection string) (value string, err error) { c := client.pool.Get() defer utils.Close(c) value, err = redis.String(c.Do("GET", collection)) if err != nil { return "", trace.TraceError(err) } return value, nil } func (client *Client) Set(collection string, value string) (err error) { c := client.pool.Get() defer utils.Close(c) value, err = redis.String(c.Do("SET", collection, value)) if err != nil { return trace.TraceError(err) } return nil } func (client *Client) Del(collection string) error { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("DEL", collection); err != nil { return trace.TraceError(err) } return nil } func (client *Client) RPush(collection string, value interface{}) error { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("RPUSH", collection, value); err != nil { return trace.TraceError(err) } return nil } func (client *Client) LPush(collection string, value interface{}) error { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("LPUSH", collection, value); err != nil { if err != redis.ErrNil { return trace.TraceError(err) } return err } return nil } func (client *Client) LPop(collection string) (string, error) { c := client.pool.Get() defer utils.Close(c) value, err := redis.String(c.Do("LPOP", collection)) if err != nil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } return value, nil } func (client *Client) RPop(collection string) (string, error) { c := client.pool.Get() defer utils.Close(c) value, err := redis.String(c.Do("RPOP", collection)) if err != nil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } return value, nil } func (client *Client) LLen(collection string) (int, error) { c := client.pool.Get() defer utils.Close(c) value, err := redis.Int(c.Do("LLEN", collection)) if err != nil { return 0, trace.TraceError(err) } return value, nil } func (client *Client) BRPop(collection string, timeout int) (value string, err error) { if timeout <= 0 { timeout = 60 } c := client.pool.Get() defer utils.Close(c) values, err := redis.Strings(c.Do("BRPOP", collection, timeout)) if err != nil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } return values[1], nil } func (client *Client) BLPop(collection string, timeout int) (value string, err error) { if timeout <= 0 { timeout = 60 } c := client.pool.Get() defer utils.Close(c) values, err := redis.Strings(c.Do("BLPOP", collection, timeout)) if err != nil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } return values[1], nil } func (client *Client) HSet(collection string, key string, value string) error { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("HSET", collection, key, value); err != nil { if err != redis.ErrNil { return trace.TraceError(err) } return err } return nil } func (client *Client) HGet(collection string, key string) (string, error) { c := client.pool.Get() defer utils.Close(c) value, err := redis.String(c.Do("HGET", collection, key)) if err != nil && err != redis.ErrNil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } return value, nil } func (client *Client) HDel(collection string, key string) error { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("HDEL", collection, key); err != nil { return trace.TraceError(err) } return nil } func (client *Client) HScan(collection string) (results map[string]string, err error) { c := client.pool.Get() defer utils.Close(c) var ( cursor int64 items []string ) results = map[string]string{} for { values, err := redis.Values(c.Do("HSCAN", collection, cursor)) if err != nil { if err != redis.ErrNil { return nil, trace.TraceError(err) } return nil, err } values, err = redis.Scan(values, &cursor, &items) if err != nil { if err != redis.ErrNil { return nil, trace.TraceError(err) } return nil, err } for i := 0; i < len(items); i += 2 { key := items[i] value := items[i+1] results[key] = value } if cursor == 0 { break } } return results, nil } func (client *Client) HKeys(collection string) (results []string, err error) { c := client.pool.Get() defer utils.Close(c) results, err = redis.Strings(c.Do("HKEYS", collection)) if err != nil { if err != redis.ErrNil { return results, trace.TraceError(err) } return results, err } return results, nil } func (client *Client) ZAdd(collection string, score float32, value interface{}) (err error) { c := client.pool.Get() defer utils.Close(c) if _, err := c.Do("ZADD", collection, score, value); err != nil { return trace.TraceError(err) } return nil } func (client *Client) ZCount(collection string, min string, max string) (count int, err error) { c := client.pool.Get() defer utils.Close(c) count, err = redis.Int(c.Do("ZCOUNT", collection, min, max)) if err != nil { return 0, trace.TraceError(err) } return count, nil } func (client *Client) ZCountAll(collection string) (count int, err error) { return client.ZCount(collection, "-inf", "+inf") } func (client *Client) ZScan(collection string, pattern string, count int) (values []string, err error) { c := client.pool.Get() defer utils.Close(c) values, err = redis.Strings(c.Do("ZSCAN", collection, 0, pattern, count)) if err != nil { if err != redis.ErrNil { return nil, trace.TraceError(err) } return nil, err } return values, nil } func (client *Client) ZPopMax(collection string, count int) (results []string, err error) { c := client.pool.Get() defer utils.Close(c) results = []string{} values, err := redis.Strings(c.Do("ZPOPMAX", collection, count)) if err != nil { if err != redis.ErrNil { return nil, trace.TraceError(err) } return nil, err } for i := 0; i < len(values); i += 2 { v := values[i] results = append(results, v) } return results, nil } func (client *Client) ZPopMin(collection string, count int) (results []string, err error) { c := client.pool.Get() defer utils.Close(c) results = []string{} values, err := redis.Strings(c.Do("ZPOPMIN", collection, count)) if err != nil { if err != redis.ErrNil { return nil, trace.TraceError(err) } return nil, err } for i := 0; i < len(values); i += 2 { v := values[i] results = append(results, v) } return results, nil } func (client *Client) ZPopMaxOne(collection string) (value string, err error) { c := client.pool.Get() defer utils.Close(c) values, err := client.ZPopMax(collection, 1) if err != nil { return "", err } if values == nil || len(values) == 0 { return "", nil } return values[0], nil } func (client *Client) ZPopMinOne(collection string) (value string, err error) { c := client.pool.Get() defer utils.Close(c) values, err := client.ZPopMin(collection, 1) if err != nil { return "", err } if values == nil || len(values) == 0 { return "", nil } return values[0], nil } func (client *Client) BZPopMax(collection string, timeout int) (value string, err error) { c := client.pool.Get() defer utils.Close(c) values, err := redis.Strings(c.Do("BZPOPMAX", collection, timeout)) if err != nil { if err != redis.ErrNil { return "", trace.TraceError(err) } return "", err } if len(values) < 3 { return "", trace.TraceError(errors.ErrorRedisInvalidType) } return values[1], nil } func (client *Client) BZPopMin(collection string, timeout int) (value string, err error) { c := client.pool.Get() defer utils.Close(c) values, err := redis.Strings(c.Do("BZPOPMIN", collection, timeout)) if err != nil { if err != redis.ErrNil { return "", trace.TraceError(err) } return "", err } if len(values) < 3 { return "", trace.TraceError(errors.ErrorRedisInvalidType) } return values[1], nil } func (client *Client) Lock(lockKey string) (value int64, err error) { c := client.pool.Get() defer utils.Close(c) lockKey = client.getLockKey(lockKey) ts := time.Now().Unix() ok, err := c.Do("SET", lockKey, ts, "NX", "PX", 30000) if err != nil { if err != redis.ErrNil { return value, trace.TraceError(err) } return value, err } if ok == nil { return 0, trace.TraceError(errors.ErrorRedisLocked) } return ts, nil } func (client *Client) UnLock(lockKey string, value int64) { c := client.pool.Get() defer utils.Close(c) lockKey = client.getLockKey(lockKey) getValue, err := redis.Int64(c.Do("GET", lockKey)) if err != nil { log.Errorf("get lockKey error: %s", err.Error()) 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()) return } if v == 0 { log.Errorf("unlock failed: key=%s", lockKey) return } } func (client *Client) MemoryStats() (stats map[string]int64, err error) { stats = map[string]int64{} c := client.pool.Get() defer utils.Close(c) values, err := redis.Values(c.Do("MEMORY", "STATS")) for i, v := range values { t := reflect.TypeOf(v) if t.Kind() == reflect.Slice { vc, _ := redis.String(v, err) if utils.ContainsString(MemoryStatsMetrics, vc) { stats[vc], _ = redis.Int64(values[i+1], err) } } } if err != nil { if err != redis.ErrNil { return stats, trace.TraceError(err) } return stats, err } return stats, nil } func (client *Client) SetBackoffMaxInterval(interval time.Duration) { client.backoffMaxInterval = interval } func (client *Client) SetTimeout(timeout int) { client.timeout = timeout } func (client *Client) init() (err error) { b := backoff.NewExponentialBackOff() b.MaxInterval = client.backoffMaxInterval if err := backoff.Retry(func() error { err := client.Ping() if err != nil { log.WithError(err).Warnf("waiting for redis pool active connection. will after %f seconds try again.", b.NextBackOff().Seconds()) } return nil }, b); err != nil { return trace.TraceError(err) } return nil } func (client *Client) getLockKey(lockKey string) string { lockKey = strings.ReplaceAll(lockKey, ":", "-") return "nodes:lock:" + lockKey } func (client *Client) getTimeout(timeout int) (res int) { if timeout == 0 { return client.timeout } return timeout } var client db.RedisClient func NewRedisClient(opts ...Option) (client *Client, err error) { // client client = &Client{ backoffMaxInterval: 20 * time.Second, pool: NewRedisPool(), } // apply options for _, opt := range opts { opt(client) } // init if err := client.init(); err != nil { return nil, err } return client, nil } func GetRedisClient() (c db.RedisClient, err error) { if client != nil { return client, nil } c, err = NewRedisClient() if err != nil { return nil, err } return c, nil } ================================================ FILE: db/redis/constants.go ================================================ package redis var MemoryStatsMetrics = []string{ "peak.allocated", "total.allocated", "startup.allocated", "overhead.total", "keys.count", "dataset.bytes", } ================================================ FILE: db/redis/options.go ================================================ package redis import ( "github.com/crawlab-team/crawlab/db" "time" ) type Option func(c db.RedisClient) func WithBackoffMaxInterval(interval time.Duration) Option { return func(c db.RedisClient) { c.SetBackoffMaxInterval(interval) } } func WithTimeout(timeout int) Option { return func(c db.RedisClient) { c.SetTimeout(timeout) } } ================================================ FILE: db/redis/pool.go ================================================ package redis import ( "github.com/crawlab-team/crawlab/trace" "github.com/gomodule/redigo/redis" "github.com/spf13/viper" "time" ) 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") // normalize params if address == "" { address = "localhost" } if port == "" { port = "6379" } if database == "" { database = "1" } 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 trace.TraceError(err) }, MaxIdle: 10, MaxActive: 0, IdleTimeout: 300 * time.Second, Wait: false, MaxConnLifetime: 0, } } ================================================ FILE: db/redis/test/base.go ================================================ package test import ( "github.com/crawlab-team/crawlab/db" "github.com/crawlab-team/crawlab/db/redis" "testing" ) func init() { var err error T, err = NewTest() if err != nil { panic(err) } } type Test struct { client db.RedisClient TestCollection string TestMessage string TestMessages []string TestMessagesMap map[string]string TestKeysAlpha []string TestKeysBeta []string TestLockKey string } func (t *Test) Setup(t2 *testing.T) { t2.Cleanup(t.Cleanup) } func (t *Test) Cleanup() { keys, _ := t.client.AllKeys() for _, key := range keys { _ = t.client.Del(key) } } var T *Test func NewTest() (t *Test, err error) { // test t = &Test{} // client t.client, err = redis.GetRedisClient() if err != nil { return nil, err } // test collection t.TestCollection = "test_collection" // test message t.TestMessage = "this is a test message" // test messages t.TestMessages = []string{ "test message 1", "test message 2", "test message 3", } // test messages map t.TestMessagesMap = map[string]string{ "test key 1": "test value 1", "test key 2": "test value 2", "test key 3": "test value 3", } // test keys alpha t.TestKeysAlpha = []string{ "test key alpha 1", "test key alpha 2", "test key alpha 3", } // test keys beta t.TestKeysBeta = []string{ "test key beta 1", "test key beta 2", "test key beta 3", "test key beta 4", "test key beta 5", } // test lock key t.TestLockKey = "test lock key" return t, nil } ================================================ FILE: db/redis/test/client_test.go ================================================ package test import ( "github.com/crawlab-team/crawlab/db/redis" "github.com/stretchr/testify/require" "testing" "time" ) func TestRedisClient_Ping(t *testing.T) { var err error T.Setup(t) err = T.client.Ping() require.Nil(t, err) } func TestRedisClient_Get_Set(t *testing.T) { var err error T.Setup(t) err = T.client.Set(T.TestCollection, T.TestMessage) require.Nil(t, err) value, err := T.client.Get(T.TestCollection) require.Nil(t, err) require.Equal(t, T.TestMessage, value) } func TestRedisClient_Keys_AllKeys(t *testing.T) { var err error T.Setup(t) for _, key := range T.TestKeysAlpha { err = T.client.Set(key, key) require.Nil(t, err) } for _, key := range T.TestKeysBeta { err = T.client.Set(key, key) require.Nil(t, err) } keys, err := T.client.Keys("*alpha*") require.Nil(t, err) require.Len(t, keys, len(T.TestKeysAlpha)) keys, err = T.client.Keys("*beta*") require.Nil(t, err) require.Len(t, keys, len(T.TestKeysBeta)) keys, err = T.client.AllKeys() require.Nil(t, err) require.Len(t, keys, len(T.TestKeysAlpha)+len(T.TestKeysBeta)) } func TestRedisClient_RPush_LPop_LLen(t *testing.T) { var err error T.Setup(t) for _, msg := range T.TestMessages { err = T.client.RPush(T.TestCollection, msg) require.Nil(t, err) } n, err := T.client.LLen(T.TestCollection) require.Nil(t, err) require.Equal(t, len(T.TestMessages), n) value, err := T.client.LPop(T.TestCollection) require.Nil(t, err) require.Equal(t, T.TestMessages[0], value) } func TestRedisClient_LPush_RPop(t *testing.T) { var err error T.Setup(t) for _, msg := range T.TestMessages { err = T.client.LPush(T.TestCollection, msg) require.Nil(t, err) } n, err := T.client.LLen(T.TestCollection) require.Nil(t, err) require.Equal(t, len(T.TestMessages), n) value, err := T.client.RPop(T.TestCollection) require.Nil(t, err) require.Equal(t, T.TestMessages[0], value) } func TestRedisClient_BRPop(t *testing.T) { var err error T.Setup(t) isErr := true go func(t *testing.T) { value, err := T.client.BRPop(T.TestCollection, 0) require.Nil(t, err) require.Equal(t, T.TestMessage, value) isErr = false }(t) err = T.client.LPush(T.TestCollection, T.TestMessage) require.Nil(t, err) time.Sleep(500 * time.Millisecond) require.False(t, isErr) } func TestRedisClient_BLPop(t *testing.T) { var err error T.Setup(t) isErr := true go func(t *testing.T) { value, err := T.client.BLPop(T.TestCollection, 0) require.Nil(t, err) require.Equal(t, T.TestMessage, value) isErr = false }(t) err = T.client.RPush(T.TestCollection, T.TestMessage) require.Nil(t, err) time.Sleep(500 * time.Millisecond) require.False(t, isErr) } func TestRedisClient_HSet_HGet_HDel(t *testing.T) { var err error T.Setup(t) for k, v := range T.TestMessagesMap { err = T.client.HSet(T.TestCollection, k, v) require.Nil(t, err) } for k, v := range T.TestMessagesMap { vr, err := T.client.HGet(T.TestCollection, k) require.Nil(t, err) require.Equal(t, v, vr) } for k := range T.TestMessagesMap { err = T.client.HDel(T.TestCollection, k) require.Nil(t, err) v, err := T.client.HGet(T.TestCollection, k) require.Nil(t, err) require.Empty(t, v) } } func TestRedisClient_HScan(t *testing.T) { var err error T.Setup(t) for k, v := range T.TestMessagesMap { err = T.client.HSet(T.TestCollection, k, v) require.Nil(t, err) } results, err := T.client.HScan(T.TestCollection) require.Nil(t, err) for k, vr := range results { v, ok := T.TestMessagesMap[k] require.True(t, ok) require.Equal(t, v, vr) } } func TestRedisClient_HKeys(t *testing.T) { var err error T.Setup(t) for k, v := range T.TestMessagesMap { err = T.client.HSet(T.TestCollection, k, v) require.Nil(t, err) } keys, err := T.client.HKeys(T.TestCollection) require.Nil(t, err) for _, k := range keys { _, ok := T.TestMessagesMap[k] require.True(t, ok) } } func TestRedisClient_ZAdd_ZCount_ZCountAll_ZPopMax_ZPopMin(t *testing.T) { var err error T.Setup(t) for i, v := range T.TestMessages { score := float32(i) err = T.client.ZAdd(T.TestCollection, score, v) require.Nil(t, err) } count, err := T.client.ZCountAll(T.TestCollection) require.Nil(t, err) require.Equal(t, len(T.TestMessages), count) value, err := T.client.ZPopMaxOne(T.TestCollection) require.Nil(t, err) require.Equal(t, T.TestMessages[len(T.TestMessages)-1], value) value, err = T.client.ZPopMinOne(T.TestCollection) require.Nil(t, err) require.Equal(t, T.TestMessages[0], value) } func TestRedisClient_BZPopMax_BZPopMin(t *testing.T) { var err error T.Setup(t) isErr := true go func(t *testing.T) { value, err := T.client.BZPopMax(T.TestCollection, 0) require.Nil(t, err) require.Equal(t, T.TestMessage, value) isErr = false }(t) err = T.client.ZAdd(T.TestCollection, 1, T.TestMessage) require.Nil(t, err) time.Sleep(500 * time.Millisecond) require.False(t, isErr) isErr = true go func(t *testing.T) { value, err := T.client.BZPopMin(T.TestCollection, 0) require.Nil(t, err) require.Equal(t, T.TestMessage, value) isErr = false }(t) err = T.client.ZAdd(T.TestCollection, 1, T.TestMessage) require.Nil(t, err) time.Sleep(500 * time.Millisecond) require.False(t, isErr) } func TestRedisClient_Lock_Unlock(t *testing.T) { var err error T.Setup(t) ts, err := T.client.Lock(T.TestLockKey) require.Nil(t, err) _, err = T.client.Lock(T.TestLockKey) require.NotNil(t, err) T.client.UnLock(T.TestLockKey, ts) ts, err = T.client.Lock(T.TestLockKey) require.Nil(t, err) } func TestRedisClient_MemoryStats(t *testing.T) { var err error T.Setup(t) stats, err := T.client.MemoryStats() require.Nil(t, err) for _, k := range redis.MemoryStatsMetrics { v, ok := stats[k] require.True(t, ok) require.Greater(t, v, int64(-1)) } } ================================================ FILE: db/sql/sql.go ================================================ package sql import ( "errors" "fmt" "github.com/crawlab-team/crawlab/trace" "github.com/jmoiron/sqlx" ) func GetSqlDatabaseConnectionString(dataSourceType string, host string, port string, username string, password string, database string) (connStr string, err error) { if dataSourceType == "mysql" { connStr = fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", username, password, host, port, database) } else if dataSourceType == "postgres" { connStr = fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s", host, port, username, database, password, "disable") } else { err = errors.New(dataSourceType + " is not implemented") return connStr, trace.TraceError(err) } return connStr, nil } func GetSqlConn(dataSourceType string, host string, port string, username string, password string, database string) (db *sqlx.DB, err error) { // get database connection string connStr, err := GetSqlDatabaseConnectionString(dataSourceType, host, port, username, password, database) if err != nil { return db, trace.TraceError(err) } // get database instance db, err = sqlx.Open(dataSourceType, connStr) if err != nil { return db, trace.TraceError(err) } return db, nil } ================================================ FILE: db/utils/utils.go ================================================ package utils import "io" func Close(c io.Closer) { err := c.Close() if err != nil { //log.WithError(err).Error("关闭资源文件失败。") } } func ContainsString(list []string, item string) bool { for _, d := range list { if d == item { return true } } return false } ================================================ FILE: devops/develop/crawlab-master.yaml ================================================ apiVersion: v1 kind: Service metadata: name: crawlab namespace: crawlab-develop spec: ports: - port: 8080 targetPort: 8080 nodePort: 30108 selector: app: crawlab-master type: NodePort --- apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-master namespace: crawlab-develop spec: serviceName: crawlab-master selector: matchLabels: app: crawlab-master template: metadata: labels: app: crawlab-master spec: containers: - image: tikazyq/crawlab:develop imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "Y" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SETTING_ALLOWREGISTER value: "Y" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ports: - containerPort: 8080 name: crawlab ================================================ FILE: devops/develop/crawlab-worker.yaml ================================================ apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-worker namespace: crawlab-develop spec: serviceName: crawlab-worker replicas: 2 selector: matchLabels: app: crawlab-worker template: metadata: labels: app: crawlab-worker spec: containers: - image: tikazyq/crawlab:develop imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "N" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ================================================ FILE: devops/develop/mongo-pv.yaml ================================================ apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv-volume-develop namespace: crawlab-develop labels: type: local spec: storageClassName: manual capacity: storage: 2Gi accessModes: - ReadWriteOnce hostPath: path: "/data/crawlab-develop/mongodb/data" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pv-claim-develop namespace: crawlab-develop spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 2Gi ================================================ FILE: devops/develop/mongo.yaml ================================================ apiVersion: v1 kind: Service metadata: name: mongo namespace: crawlab-develop spec: ports: - port: 27017 selector: app: mongo clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: mongo namespace: crawlab-develop spec: selector: matchLabels: app: mongo strategy: type: Recreate template: metadata: labels: app: mongo spec: containers: - image: mongo:4 name: mongo ports: - containerPort: 27017 name: mongo volumeMounts: - name: mongo-persistent-storage mountPath: /data/db volumes: - name: mongo-persistent-storage persistentVolumeClaim: claimName: mongo-pv-claim-develop ================================================ FILE: devops/develop/ns.yaml ================================================ apiVersion: v1 kind: Namespace metadata: name: crawlab-develop ================================================ FILE: devops/develop/redis.yaml ================================================ apiVersion: v1 kind: Service metadata: name: redis namespace: crawlab-develop spec: ports: - port: 6379 selector: app: redis clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: redis namespace: crawlab-develop spec: selector: matchLabels: app: redis strategy: type: Recreate template: metadata: labels: app: redis spec: containers: - image: redis name: redis ports: - containerPort: 6379 name: redis ================================================ FILE: devops/master/crawlab-master.yaml ================================================ apiVersion: v1 kind: Service metadata: name: crawlab namespace: crawlab spec: ports: - port: 8080 targetPort: 8080 nodePort: 30088 selector: app: crawlab-master type: NodePort --- apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-master namespace: crawlab spec: serviceName: crawlab-master selector: matchLabels: app: crawlab-master template: metadata: labels: app: crawlab-master spec: containers: - image: tikazyq/crawlab:latest imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "Y" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" - name: CRAWLAB_SETTING_ALLOWREGISTER value: "Y" - name: CRAWLAB_SETTING_ENABLETUTORIAL value: "Y" - name: CRAWLAB_SETTING_DEMOSPIDERS value: "Y" ports: - containerPort: 8080 name: crawlab ================================================ FILE: devops/master/crawlab-worker.yaml ================================================ apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-worker namespace: crawlab spec: serviceName: crawlab-worker replicas: 2 selector: matchLabels: app: crawlab-worker template: metadata: labels: app: crawlab-worker spec: containers: - image: tikazyq/crawlab:latest imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "N" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SERVER_LANG_NODE value: "Y" - name: CRAWLAB_SERVER_LANG_JAVA value: "Y" - name: CRAWLAB_SERVER_LANG_DOTNET value: "Y" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ================================================ FILE: devops/master/mongo-pv.yaml ================================================ apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv-volume namespace: crawlab labels: type: local spec: storageClassName: manual capacity: storage: 3Gi accessModes: - ReadWriteOnce hostPath: path: "/data/k8s/mongodb/data" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pv-claim namespace: crawlab spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 3Gi ================================================ FILE: devops/master/mongo.yaml ================================================ apiVersion: v1 kind: Service metadata: name: mongo namespace: crawlab spec: ports: - port: 27017 selector: app: mongo clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: mongo namespace: crawlab spec: selector: matchLabels: app: mongo strategy: type: Recreate template: metadata: labels: app: mongo spec: containers: - image: mongo:4 name: mongo ports: - containerPort: 27017 name: mongo volumeMounts: - name: mongo-persistent-storage mountPath: /data/db volumes: - name: mongo-persistent-storage persistentVolumeClaim: claimName: mongo-pv-claim ================================================ FILE: devops/master/ns.yaml ================================================ apiVersion: v1 kind: Namespace metadata: name: crawlab ================================================ FILE: devops/master/redis.yaml ================================================ apiVersion: v1 kind: Service metadata: name: redis namespace: crawlab spec: ports: - port: 6379 selector: app: redis clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: redis namespace: crawlab spec: selector: matchLabels: app: redis strategy: type: Recreate template: metadata: labels: app: redis spec: containers: - image: redis name: redis ports: - containerPort: 6379 name: redis ================================================ FILE: devops/release/crawlab-master.yaml ================================================ apiVersion: v1 kind: Service metadata: name: crawlab namespace: crawlab-release spec: ports: - port: 8080 targetPort: 8080 nodePort: 30098 selector: app: crawlab-master type: NodePort --- apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-master namespace: crawlab-release spec: serviceName: crawlab-master selector: matchLabels: app: crawlab-master template: metadata: labels: app: crawlab-master spec: containers: - image: tikazyq/crawlab:release imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "Y" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SETTING_ALLOWREGISTER value: "Y" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ports: - containerPort: 8080 name: crawlab ================================================ FILE: devops/release/crawlab-worker.yaml ================================================ apiVersion: apps/v1 kind: StatefulSet metadata: name: crawlab-worker namespace: crawlab-release spec: serviceName: crawlab-worker replicas: 2 selector: matchLabels: app: crawlab-worker template: metadata: labels: app: crawlab-worker spec: containers: - image: tikazyq/crawlab:release imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_SERVER_MASTER value: "N" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ================================================ FILE: devops/release/mongo-pv.yaml ================================================ apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv-volume-release namespace: crawlab-release labels: type: local spec: storageClassName: manual capacity: storage: 5Gi accessModes: - ReadWriteOnce hostPath: path: "/data/crawlab-release/mongodb/data" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pv-claim-release namespace: crawlab-release spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 5Gi ================================================ FILE: devops/release/mongo.yaml ================================================ apiVersion: v1 kind: Service metadata: name: mongo namespace: crawlab-release spec: ports: - port: 27017 selector: app: mongo clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: mongo namespace: crawlab-release spec: selector: matchLabels: app: mongo strategy: type: Recreate template: metadata: labels: app: mongo spec: containers: - image: mongo:4 name: mongo ports: - containerPort: 27017 name: mongo volumeMounts: - name: mongo-persistent-storage mountPath: /data/db volumes: - name: mongo-persistent-storage persistentVolumeClaim: claimName: mongo-pv-claim-release ================================================ FILE: devops/release/ns.yaml ================================================ apiVersion: v1 kind: Namespace metadata: name: crawlab-release ================================================ FILE: devops/release/redis.yaml ================================================ apiVersion: v1 kind: Service metadata: name: redis namespace: crawlab-release spec: ports: - port: 6379 selector: app: redis clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: redis namespace: crawlab-release spec: selector: matchLabels: app: redis strategy: type: Recreate template: metadata: labels: app: redis spec: containers: - image: redis name: redis ports: - containerPort: 6379 name: redis ================================================ FILE: docker-compose.yml ================================================ version: '3.3' services: master: image: crawlabteam/crawlab container_name: crawlab_master environment: CRAWLAB_NODE_MASTER: "Y" CRAWLAB_MONGO_HOST: "mongo" ports: - "8080:8080" depends_on: - mongo mongo: image: mongo:4.2 ================================================ FILE: docs/config.md ================================================ # Config #### Environment Variable List Name | Description | Example | Default ---|--- | --- | --- CRAWLAB_GRPC_ADDRESS| Target gRPC address the nodes are connecting to | 192.168.0.1:9666 | localhost:9666 CRAWLAB_GRPC_SERVER_ADDRESS| Address that the gRPC server is listening to (master node only) | 0.0.0.0:9666 | 0.0.0.0:9666 CRAWLAB_GRPC_AUTHKEY| The token that gRPC clients and server use for authentication | youcanneverguess | Crawlab2021! CRAWLAB_NODE_MASTER | Whether the current node is a master or worker node (Y: master; N: worker) | Y | Y CRAWLAB_SERVER_HOST | IP host that the API listens to (master node only) | 0.0.0.0 | 0.0.0.0 CRAWLAB_SERVER_PORT | IP port that the API listens to (master node only) | 8000 | 8000 CRAWLAB_TASK_HANDLER_MAXRUNNERS | Max number of task runners (concurrent spider tasks) that a node can run | 16 | 8 CRAWLAB_FS_FILER_PROXY |Filer API endpoint that Crawlab's filer proxy links to |http://filer-server:8888 | http://localhost:8888 CRAWLAB_FS_FILER_URL |Crawlab's Filer API endpoint |http://crawlab-web-api:8000/filer | http://localhost:8000/filer CRAWLAB_FS_FILER_AUTHKEY |Crawlab's Filer API auth key token | youcanneverguess | Crawlab2021! ================================================ FILE: frontend/.editorconfig ================================================ root = true [*] tab_width = 2 # 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 [*.ts] indent_size = 2 [*.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 [vue.config.js] indent_size = 2 tab_width = 2 ================================================ FILE: frontend/.eslintignore ================================================ ./src/i18n/**/*.ts */**/*.js *.js ================================================ FILE: frontend/.eslintrc.js ================================================ module.exports = { root: true, env: { node: true }, 'extends': [ 'plugin:vue/vue3-essential', 'eslint:recommended', '@vue/typescript/recommended' ], parserOptions: { ecmaVersion: 2020 }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', '@typescript-eslint/no-explicit-any': process.env.NODE_ENV === 'production' ? 'warn' : 'off', '@typescript-eslint/camelcase': process.env.NODE_ENV === 'production' ? 'warn' : 'off', } } ================================================ FILE: frontend/.gitignore ================================================ .DS_Store node_modules /dist # local env files .env.local .env.*.local # Log files npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw? tmp/ lib/ **/.DS_Store **/.idea **/dist **/node_modules **/package-lock.json stats.html ================================================ FILE: frontend/.npmrc ================================================ registry=https://registry.npmjs.org ================================================ FILE: frontend/Dockerfile ================================================ FROM node:14 AS build ADD . /app WORKDIR /app RUN rm /app/.npmrc # install frontend RUN npm i -g pnpm@7 RUN pnpm install RUN pnpm run build FROM alpine:3.14 # copy files COPY --from=build /app/dist /app/dist ================================================ FILE: frontend/babel.config.js ================================================ module.exports = { presets: [ '@vue/cli-plugin-babel/preset', '@babel/preset-typescript' ] } ================================================ FILE: frontend/index.html ================================================ Crawlab

C R A W L A B

Easy Crawling Better Management Gain Data Value Good Scalability
Loading...
================================================ FILE: frontend/jest.config.ts ================================================ /* * 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, }; ================================================ FILE: frontend/package.json ================================================ { "name": "@crawlab/app", "version": "0.6.3", "scripts": { "serve": "vite", "serve:dist": "serve dist", "build": "vite build", "build:docker": "vite build --mode docker" }, "author": { "name": "Marvin Zhang", "email": "tikazyq@163.com" }, "license": "BSD-3-Clause", "dependencies": { "@element-plus/icons": "^0.0.11", "@fortawesome/fontawesome-svg-core": "^1.3.0", "@fortawesome/free-brands-svg-icons": "^6.0.0", "@fortawesome/free-regular-svg-icons": "^6.0.0", "@fortawesome/free-solid-svg-icons": "^6.0.0", "@fortawesome/vue-fontawesome": "^3.0.0-5", "atom-material-icons": "^3.0.0", "codemirror": "^5.59.1", "crawlab-ui": "0.6.3", "echarts": "^5.1.2", "element-plus": "^1.3.0-beta.10", "vue": "^3.2", "vue-router": "^4.0.11" }, "devDependencies": { "@types/node": "^18.11.10", "@vitejs/plugin-vue": "^3.2.0", "@vue/compiler-sfc": "^3.2.45", "rollup-plugin-external-globals": "^0.8.0", "rollup-plugin-visualizer": "^5.9.2", "typescript": "^4.6.4", "vite": "^3.2.4", "vite-aliases": "^0.9.7", "vite-plugin-dynamic-import": "^1.2.4", "vite-plugin-externalize-deps": "^0.7.0", "vue-tsc": "^1.0.9" } } ================================================ FILE: frontend/public/js/login-canvas.js ================================================ 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') if (!canvas) return; 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, {passive: true}) // 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 } ================================================ FILE: frontend/public/js/vue3-sfc-loader.js ================================================ /*! * vue3-sfc-loader v0.8.4 for vue3 * * @description Vue3 Single File Component loader. * @author Franck FREIBURGER * @license MIT * @sources https://github.com/FranckFreiburger/vue3-sfc-loader */ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["vue3-sfc-loader"]=t():e["vue3-sfc-loader"]=t()}(self,(function(){return(()=>{var e=[(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n={react:!0,assertNode:!0,createTypeAnnotationBasedOnTypeof:!0,createUnionTypeAnnotation:!0,createFlowUnionType:!0,createTSUnionType:!0,cloneNode:!0,clone:!0,cloneDeep:!0,cloneDeepWithoutLoc:!0,cloneWithoutLoc:!0,addComment:!0,addComments:!0,inheritInnerComments:!0,inheritLeadingComments:!0,inheritsComments:!0,inheritTrailingComments:!0,removeComments:!0,ensureBlock:!0,toBindingIdentifierName:!0,toBlock:!0,toComputedKey:!0,toExpression:!0,toIdentifier:!0,toKeyAlias:!0,toSequenceExpression:!0,toStatement:!0,valueToNode:!0,appendToMemberExpression:!0,inherits:!0,prependToMemberExpression:!0,removeProperties:!0,removePropertiesDeep:!0,removeTypeDuplicates:!0,getBindingIdentifiers:!0,getOuterBindingIdentifiers:!0,traverse:!0,traverseFast:!0,shallowEqual:!0,is:!0,isBinding:!0,isBlockScoped:!0,isImmutable:!0,isLet:!0,isNode:!0,isNodesEquivalent:!0,isPlaceholderType:!0,isReferenced:!0,isScope:!0,isSpecifierDefault:!0,isType:!0,isValidES3Identifier:!0,isValidIdentifier:!0,isVar:!0,matchesPattern:!0,validate:!0,buildMatchMemberExpression:!0};Object.defineProperty(t,"assertNode",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"createTypeAnnotationBasedOnTypeof",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"createUnionTypeAnnotation",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"createFlowUnionType",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"createTSUnionType",{enumerable:!0,get:function(){return p.default}}),Object.defineProperty(t,"cloneNode",{enumerable:!0,get:function(){return h.default}}),Object.defineProperty(t,"clone",{enumerable:!0,get:function(){return m.default}}),Object.defineProperty(t,"cloneDeep",{enumerable:!0,get:function(){return y.default}}),Object.defineProperty(t,"cloneDeepWithoutLoc",{enumerable:!0,get:function(){return g.default}}),Object.defineProperty(t,"cloneWithoutLoc",{enumerable:!0,get:function(){return b.default}}),Object.defineProperty(t,"addComment",{enumerable:!0,get:function(){return v.default}}),Object.defineProperty(t,"addComments",{enumerable:!0,get:function(){return E.default}}),Object.defineProperty(t,"inheritInnerComments",{enumerable:!0,get:function(){return x.default}}),Object.defineProperty(t,"inheritLeadingComments",{enumerable:!0,get:function(){return S.default}}),Object.defineProperty(t,"inheritsComments",{enumerable:!0,get:function(){return T.default}}),Object.defineProperty(t,"inheritTrailingComments",{enumerable:!0,get:function(){return w.default}}),Object.defineProperty(t,"removeComments",{enumerable:!0,get:function(){return P.default}}),Object.defineProperty(t,"ensureBlock",{enumerable:!0,get:function(){return C.default}}),Object.defineProperty(t,"toBindingIdentifierName",{enumerable:!0,get:function(){return I.default}}),Object.defineProperty(t,"toBlock",{enumerable:!0,get:function(){return k.default}}),Object.defineProperty(t,"toComputedKey",{enumerable:!0,get:function(){return N.default}}),Object.defineProperty(t,"toExpression",{enumerable:!0,get:function(){return _.default}}),Object.defineProperty(t,"toIdentifier",{enumerable:!0,get:function(){return j.default}}),Object.defineProperty(t,"toKeyAlias",{enumerable:!0,get:function(){return D.default}}),Object.defineProperty(t,"toSequenceExpression",{enumerable:!0,get:function(){return L.default}}),Object.defineProperty(t,"toStatement",{enumerable:!0,get:function(){return M.default}}),Object.defineProperty(t,"valueToNode",{enumerable:!0,get:function(){return B.default}}),Object.defineProperty(t,"appendToMemberExpression",{enumerable:!0,get:function(){return F.default}}),Object.defineProperty(t,"inherits",{enumerable:!0,get:function(){return U.default}}),Object.defineProperty(t,"prependToMemberExpression",{enumerable:!0,get:function(){return $.default}}),Object.defineProperty(t,"removeProperties",{enumerable:!0,get:function(){return q.default}}),Object.defineProperty(t,"removePropertiesDeep",{enumerable:!0,get:function(){return V.default}}),Object.defineProperty(t,"removeTypeDuplicates",{enumerable:!0,get:function(){return W.default}}),Object.defineProperty(t,"getBindingIdentifiers",{enumerable:!0,get:function(){return K.default}}),Object.defineProperty(t,"getOuterBindingIdentifiers",{enumerable:!0,get:function(){return G.default}}),Object.defineProperty(t,"traverse",{enumerable:!0,get:function(){return H.default}}),Object.defineProperty(t,"traverseFast",{enumerable:!0,get:function(){return J.default}}),Object.defineProperty(t,"shallowEqual",{enumerable:!0,get:function(){return Y.default}}),Object.defineProperty(t,"is",{enumerable:!0,get:function(){return X.default}}),Object.defineProperty(t,"isBinding",{enumerable:!0,get:function(){return z.default}}),Object.defineProperty(t,"isBlockScoped",{enumerable:!0,get:function(){return Q.default}}),Object.defineProperty(t,"isImmutable",{enumerable:!0,get:function(){return Z.default}}),Object.defineProperty(t,"isLet",{enumerable:!0,get:function(){return ee.default}}),Object.defineProperty(t,"isNode",{enumerable:!0,get:function(){return te.default}}),Object.defineProperty(t,"isNodesEquivalent",{enumerable:!0,get:function(){return re.default}}),Object.defineProperty(t,"isPlaceholderType",{enumerable:!0,get:function(){return ne.default}}),Object.defineProperty(t,"isReferenced",{enumerable:!0,get:function(){return se.default}}),Object.defineProperty(t,"isScope",{enumerable:!0,get:function(){return ie.default}}),Object.defineProperty(t,"isSpecifierDefault",{enumerable:!0,get:function(){return oe.default}}),Object.defineProperty(t,"isType",{enumerable:!0,get:function(){return ae.default}}),Object.defineProperty(t,"isValidES3Identifier",{enumerable:!0,get:function(){return le.default}}),Object.defineProperty(t,"isValidIdentifier",{enumerable:!0,get:function(){return ce.default}}),Object.defineProperty(t,"isVar",{enumerable:!0,get:function(){return ue.default}}),Object.defineProperty(t,"matchesPattern",{enumerable:!0,get:function(){return pe.default}}),Object.defineProperty(t,"validate",{enumerable:!0,get:function(){return fe.default}}),Object.defineProperty(t,"buildMatchMemberExpression",{enumerable:!0,get:function(){return de.default}}),t.react=void 0;var s=r(363),i=r(364),o=r(365),a=r(375),l=r(376);Object.keys(l).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===l[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return l[e]}}))}));var c=r(377),u=r(378),p=r(379),f=r(6);Object.keys(f).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===f[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return f[e]}}))}));var d=r(381);Object.keys(d).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===d[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return d[e]}}))}));var h=r(26),m=r(382),y=r(383),g=r(384),b=r(385),v=r(386),E=r(220),x=r(221),S=r(222),T=r(223),w=r(224),P=r(387),A=r(388);Object.keys(A).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===A[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return A[e]}}))}));var O=r(25);Object.keys(O).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===O[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return O[e]}}))}));var C=r(389),I=r(390),k=r(225),N=r(391),_=r(392),j=r(226),D=r(393),L=r(394),M=r(396),B=r(397),R=r(11);Object.keys(R).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===R[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return R[e]}}))}));var F=r(398),U=r(399),$=r(400),q=r(229),V=r(227),W=r(219),K=r(64),G=r(401),H=r(402);Object.keys(H).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===H[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return H[e]}}))}));var J=r(228),Y=r(127),X=r(62),z=r(403),Q=r(404),Z=r(405),ee=r(230),te=r(218),re=r(406),ne=r(216),se=r(407),ie=r(408),oe=r(409),ae=r(129),le=r(410),ce=r(38),ue=r(411),pe=r(214),fe=r(130),de=r(213),he=r(1);Object.keys(he).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===he[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return he[e]}}))}));var me=r(412);Object.keys(me).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(n,e)||e in t&&t[e]===me[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return me[e]}}))}));const ye={isReactComponent:s.default,isCompatTag:i.default,buildChildren:o.default};t.react=ye},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isArrayExpression=function(e,t){return!!e&&("ArrayExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isAssignmentExpression=function(e,t){return!!e&&("AssignmentExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBinaryExpression=function(e,t){return!!e&&("BinaryExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isInterpreterDirective=function(e,t){return!!e&&("InterpreterDirective"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDirective=function(e,t){return!!e&&("Directive"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDirectiveLiteral=function(e,t){return!!e&&("DirectiveLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBlockStatement=function(e,t){return!!e&&("BlockStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBreakStatement=function(e,t){return!!e&&("BreakStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isCallExpression=function(e,t){return!!e&&("CallExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isCatchClause=function(e,t){return!!e&&("CatchClause"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isConditionalExpression=function(e,t){return!!e&&("ConditionalExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isContinueStatement=function(e,t){return!!e&&("ContinueStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDebuggerStatement=function(e,t){return!!e&&("DebuggerStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDoWhileStatement=function(e,t){return!!e&&("DoWhileStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEmptyStatement=function(e,t){return!!e&&("EmptyStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExpressionStatement=function(e,t){return!!e&&("ExpressionStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isFile=function(e,t){return!!e&&("File"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isForInStatement=function(e,t){return!!e&&("ForInStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isForStatement=function(e,t){return!!e&&("ForStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isFunctionDeclaration=function(e,t){return!!e&&("FunctionDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isFunctionExpression=function(e,t){return!!e&&("FunctionExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isIdentifier=function(e,t){return!!e&&("Identifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isIfStatement=function(e,t){return!!e&&("IfStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isLabeledStatement=function(e,t){return!!e&&("LabeledStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isStringLiteral=function(e,t){return!!e&&("StringLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNumericLiteral=function(e,t){return!!e&&("NumericLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNullLiteral=function(e,t){return!!e&&("NullLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBooleanLiteral=function(e,t){return!!e&&("BooleanLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isRegExpLiteral=function(e,t){return!!e&&("RegExpLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isLogicalExpression=function(e,t){return!!e&&("LogicalExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isMemberExpression=function(e,t){return!!e&&("MemberExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNewExpression=function(e,t){return!!e&&("NewExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isProgram=function(e,t){return!!e&&("Program"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectExpression=function(e,t){return!!e&&("ObjectExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectMethod=function(e,t){return!!e&&("ObjectMethod"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectProperty=function(e,t){return!!e&&("ObjectProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isRestElement=function(e,t){return!!e&&("RestElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isReturnStatement=function(e,t){return!!e&&("ReturnStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSequenceExpression=function(e,t){return!!e&&("SequenceExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isParenthesizedExpression=function(e,t){return!!e&&("ParenthesizedExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSwitchCase=function(e,t){return!!e&&("SwitchCase"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSwitchStatement=function(e,t){return!!e&&("SwitchStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isThisExpression=function(e,t){return!!e&&("ThisExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isThrowStatement=function(e,t){return!!e&&("ThrowStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTryStatement=function(e,t){return!!e&&("TryStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isUnaryExpression=function(e,t){return!!e&&("UnaryExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isUpdateExpression=function(e,t){return!!e&&("UpdateExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isVariableDeclaration=function(e,t){return!!e&&("VariableDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isVariableDeclarator=function(e,t){return!!e&&("VariableDeclarator"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isWhileStatement=function(e,t){return!!e&&("WhileStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isWithStatement=function(e,t){return!!e&&("WithStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isAssignmentPattern=function(e,t){return!!e&&("AssignmentPattern"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isArrayPattern=function(e,t){return!!e&&("ArrayPattern"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isArrowFunctionExpression=function(e,t){return!!e&&("ArrowFunctionExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassBody=function(e,t){return!!e&&("ClassBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassExpression=function(e,t){return!!e&&("ClassExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassDeclaration=function(e,t){return!!e&&("ClassDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportAllDeclaration=function(e,t){return!!e&&("ExportAllDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportDefaultDeclaration=function(e,t){return!!e&&("ExportDefaultDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportNamedDeclaration=function(e,t){return!!e&&("ExportNamedDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportSpecifier=function(e,t){return!!e&&("ExportSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isForOfStatement=function(e,t){return!!e&&("ForOfStatement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImportDeclaration=function(e,t){return!!e&&("ImportDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImportDefaultSpecifier=function(e,t){return!!e&&("ImportDefaultSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImportNamespaceSpecifier=function(e,t){return!!e&&("ImportNamespaceSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImportSpecifier=function(e,t){return!!e&&("ImportSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isMetaProperty=function(e,t){return!!e&&("MetaProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassMethod=function(e,t){return!!e&&("ClassMethod"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectPattern=function(e,t){return!!e&&("ObjectPattern"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSpreadElement=function(e,t){return!!e&&("SpreadElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSuper=function(e,t){return!!e&&("Super"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTaggedTemplateExpression=function(e,t){return!!e&&("TaggedTemplateExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTemplateElement=function(e,t){return!!e&&("TemplateElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTemplateLiteral=function(e,t){return!!e&&("TemplateLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isYieldExpression=function(e,t){return!!e&&("YieldExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isAwaitExpression=function(e,t){return!!e&&("AwaitExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImport=function(e,t){return!!e&&("Import"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBigIntLiteral=function(e,t){return!!e&&("BigIntLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportNamespaceSpecifier=function(e,t){return!!e&&("ExportNamespaceSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isOptionalMemberExpression=function(e,t){return!!e&&("OptionalMemberExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isOptionalCallExpression=function(e,t){return!!e&&("OptionalCallExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isAnyTypeAnnotation=function(e,t){return!!e&&("AnyTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isArrayTypeAnnotation=function(e,t){return!!e&&("ArrayTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBooleanTypeAnnotation=function(e,t){return!!e&&("BooleanTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBooleanLiteralTypeAnnotation=function(e,t){return!!e&&("BooleanLiteralTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNullLiteralTypeAnnotation=function(e,t){return!!e&&("NullLiteralTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassImplements=function(e,t){return!!e&&("ClassImplements"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareClass=function(e,t){return!!e&&("DeclareClass"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareFunction=function(e,t){return!!e&&("DeclareFunction"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareInterface=function(e,t){return!!e&&("DeclareInterface"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareModule=function(e,t){return!!e&&("DeclareModule"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareModuleExports=function(e,t){return!!e&&("DeclareModuleExports"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareTypeAlias=function(e,t){return!!e&&("DeclareTypeAlias"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareOpaqueType=function(e,t){return!!e&&("DeclareOpaqueType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareVariable=function(e,t){return!!e&&("DeclareVariable"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareExportDeclaration=function(e,t){return!!e&&("DeclareExportDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclareExportAllDeclaration=function(e,t){return!!e&&("DeclareExportAllDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDeclaredPredicate=function(e,t){return!!e&&("DeclaredPredicate"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExistsTypeAnnotation=function(e,t){return!!e&&("ExistsTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isFunctionTypeAnnotation=function(e,t){return!!e&&("FunctionTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isFunctionTypeParam=function(e,t){return!!e&&("FunctionTypeParam"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isGenericTypeAnnotation=function(e,t){return!!e&&("GenericTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isInferredPredicate=function(e,t){return!!e&&("InferredPredicate"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isInterfaceExtends=function(e,t){return!!e&&("InterfaceExtends"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isInterfaceDeclaration=function(e,t){return!!e&&("InterfaceDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isInterfaceTypeAnnotation=function(e,t){return!!e&&("InterfaceTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isIntersectionTypeAnnotation=function(e,t){return!!e&&("IntersectionTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isMixedTypeAnnotation=function(e,t){return!!e&&("MixedTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEmptyTypeAnnotation=function(e,t){return!!e&&("EmptyTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNullableTypeAnnotation=function(e,t){return!!e&&("NullableTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNumberLiteralTypeAnnotation=function(e,t){return!!e&&("NumberLiteralTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNumberTypeAnnotation=function(e,t){return!!e&&("NumberTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeAnnotation=function(e,t){return!!e&&("ObjectTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeInternalSlot=function(e,t){return!!e&&("ObjectTypeInternalSlot"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeCallProperty=function(e,t){return!!e&&("ObjectTypeCallProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeIndexer=function(e,t){return!!e&&("ObjectTypeIndexer"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeProperty=function(e,t){return!!e&&("ObjectTypeProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isObjectTypeSpreadProperty=function(e,t){return!!e&&("ObjectTypeSpreadProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isOpaqueType=function(e,t){return!!e&&("OpaqueType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isQualifiedTypeIdentifier=function(e,t){return!!e&&("QualifiedTypeIdentifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isStringLiteralTypeAnnotation=function(e,t){return!!e&&("StringLiteralTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isStringTypeAnnotation=function(e,t){return!!e&&("StringTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSymbolTypeAnnotation=function(e,t){return!!e&&("SymbolTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isThisTypeAnnotation=function(e,t){return!!e&&("ThisTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTupleTypeAnnotation=function(e,t){return!!e&&("TupleTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeofTypeAnnotation=function(e,t){return!!e&&("TypeofTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeAlias=function(e,t){return!!e&&("TypeAlias"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeAnnotation=function(e,t){return!!e&&("TypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeCastExpression=function(e,t){return!!e&&("TypeCastExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeParameter=function(e,t){return!!e&&("TypeParameter"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeParameterDeclaration=function(e,t){return!!e&&("TypeParameterDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTypeParameterInstantiation=function(e,t){return!!e&&("TypeParameterInstantiation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isUnionTypeAnnotation=function(e,t){return!!e&&("UnionTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isVariance=function(e,t){return!!e&&("Variance"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isVoidTypeAnnotation=function(e,t){return!!e&&("VoidTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumDeclaration=function(e,t){return!!e&&("EnumDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumBooleanBody=function(e,t){return!!e&&("EnumBooleanBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumNumberBody=function(e,t){return!!e&&("EnumNumberBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumStringBody=function(e,t){return!!e&&("EnumStringBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumSymbolBody=function(e,t){return!!e&&("EnumSymbolBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumBooleanMember=function(e,t){return!!e&&("EnumBooleanMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumNumberMember=function(e,t){return!!e&&("EnumNumberMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumStringMember=function(e,t){return!!e&&("EnumStringMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isEnumDefaultedMember=function(e,t){return!!e&&("EnumDefaultedMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isIndexedAccessType=function(e,t){return!!e&&("IndexedAccessType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isOptionalIndexedAccessType=function(e,t){return!!e&&("OptionalIndexedAccessType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXAttribute=function(e,t){return!!e&&("JSXAttribute"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXClosingElement=function(e,t){return!!e&&("JSXClosingElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXElement=function(e,t){return!!e&&("JSXElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXEmptyExpression=function(e,t){return!!e&&("JSXEmptyExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXExpressionContainer=function(e,t){return!!e&&("JSXExpressionContainer"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXSpreadChild=function(e,t){return!!e&&("JSXSpreadChild"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXIdentifier=function(e,t){return!!e&&("JSXIdentifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXMemberExpression=function(e,t){return!!e&&("JSXMemberExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXNamespacedName=function(e,t){return!!e&&("JSXNamespacedName"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXOpeningElement=function(e,t){return!!e&&("JSXOpeningElement"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXSpreadAttribute=function(e,t){return!!e&&("JSXSpreadAttribute"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXText=function(e,t){return!!e&&("JSXText"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXFragment=function(e,t){return!!e&&("JSXFragment"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXOpeningFragment=function(e,t){return!!e&&("JSXOpeningFragment"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isJSXClosingFragment=function(e,t){return!!e&&("JSXClosingFragment"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isNoop=function(e,t){return!!e&&("Noop"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isPlaceholder=function(e,t){return!!e&&("Placeholder"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isV8IntrinsicIdentifier=function(e,t){return!!e&&("V8IntrinsicIdentifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isArgumentPlaceholder=function(e,t){return!!e&&("ArgumentPlaceholder"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isBindExpression=function(e,t){return!!e&&("BindExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassProperty=function(e,t){return!!e&&("ClassProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isPipelineTopicExpression=function(e,t){return!!e&&("PipelineTopicExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isPipelineBareFunction=function(e,t){return!!e&&("PipelineBareFunction"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isPipelinePrimaryTopicReference=function(e,t){return!!e&&("PipelinePrimaryTopicReference"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassPrivateProperty=function(e,t){return!!e&&("ClassPrivateProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isClassPrivateMethod=function(e,t){return!!e&&("ClassPrivateMethod"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isImportAttribute=function(e,t){return!!e&&("ImportAttribute"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDecorator=function(e,t){return!!e&&("Decorator"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDoExpression=function(e,t){return!!e&&("DoExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExportDefaultSpecifier=function(e,t){return!!e&&("ExportDefaultSpecifier"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isPrivateName=function(e,t){return!!e&&("PrivateName"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isRecordExpression=function(e,t){return!!e&&("RecordExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTupleExpression=function(e,t){return!!e&&("TupleExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isDecimalLiteral=function(e,t){return!!e&&("DecimalLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isStaticBlock=function(e,t){return!!e&&("StaticBlock"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isModuleExpression=function(e,t){return!!e&&("ModuleExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSParameterProperty=function(e,t){return!!e&&("TSParameterProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSDeclareFunction=function(e,t){return!!e&&("TSDeclareFunction"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSDeclareMethod=function(e,t){return!!e&&("TSDeclareMethod"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSQualifiedName=function(e,t){return!!e&&("TSQualifiedName"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSCallSignatureDeclaration=function(e,t){return!!e&&("TSCallSignatureDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSConstructSignatureDeclaration=function(e,t){return!!e&&("TSConstructSignatureDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSPropertySignature=function(e,t){return!!e&&("TSPropertySignature"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSMethodSignature=function(e,t){return!!e&&("TSMethodSignature"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSIndexSignature=function(e,t){return!!e&&("TSIndexSignature"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSAnyKeyword=function(e,t){return!!e&&("TSAnyKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSBooleanKeyword=function(e,t){return!!e&&("TSBooleanKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSBigIntKeyword=function(e,t){return!!e&&("TSBigIntKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSIntrinsicKeyword=function(e,t){return!!e&&("TSIntrinsicKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNeverKeyword=function(e,t){return!!e&&("TSNeverKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNullKeyword=function(e,t){return!!e&&("TSNullKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNumberKeyword=function(e,t){return!!e&&("TSNumberKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSObjectKeyword=function(e,t){return!!e&&("TSObjectKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSStringKeyword=function(e,t){return!!e&&("TSStringKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSSymbolKeyword=function(e,t){return!!e&&("TSSymbolKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSUndefinedKeyword=function(e,t){return!!e&&("TSUndefinedKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSUnknownKeyword=function(e,t){return!!e&&("TSUnknownKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSVoidKeyword=function(e,t){return!!e&&("TSVoidKeyword"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSThisType=function(e,t){return!!e&&("TSThisType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSFunctionType=function(e,t){return!!e&&("TSFunctionType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSConstructorType=function(e,t){return!!e&&("TSConstructorType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeReference=function(e,t){return!!e&&("TSTypeReference"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypePredicate=function(e,t){return!!e&&("TSTypePredicate"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeQuery=function(e,t){return!!e&&("TSTypeQuery"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeLiteral=function(e,t){return!!e&&("TSTypeLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSArrayType=function(e,t){return!!e&&("TSArrayType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTupleType=function(e,t){return!!e&&("TSTupleType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSOptionalType=function(e,t){return!!e&&("TSOptionalType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSRestType=function(e,t){return!!e&&("TSRestType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNamedTupleMember=function(e,t){return!!e&&("TSNamedTupleMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSUnionType=function(e,t){return!!e&&("TSUnionType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSIntersectionType=function(e,t){return!!e&&("TSIntersectionType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSConditionalType=function(e,t){return!!e&&("TSConditionalType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSInferType=function(e,t){return!!e&&("TSInferType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSParenthesizedType=function(e,t){return!!e&&("TSParenthesizedType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeOperator=function(e,t){return!!e&&("TSTypeOperator"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSIndexedAccessType=function(e,t){return!!e&&("TSIndexedAccessType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSMappedType=function(e,t){return!!e&&("TSMappedType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSLiteralType=function(e,t){return!!e&&("TSLiteralType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSExpressionWithTypeArguments=function(e,t){return!!e&&("TSExpressionWithTypeArguments"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSInterfaceDeclaration=function(e,t){return!!e&&("TSInterfaceDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSInterfaceBody=function(e,t){return!!e&&("TSInterfaceBody"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeAliasDeclaration=function(e,t){return!!e&&("TSTypeAliasDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSAsExpression=function(e,t){return!!e&&("TSAsExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeAssertion=function(e,t){return!!e&&("TSTypeAssertion"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSEnumDeclaration=function(e,t){return!!e&&("TSEnumDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSEnumMember=function(e,t){return!!e&&("TSEnumMember"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSModuleDeclaration=function(e,t){return!!e&&("TSModuleDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSModuleBlock=function(e,t){return!!e&&("TSModuleBlock"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSImportType=function(e,t){return!!e&&("TSImportType"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSImportEqualsDeclaration=function(e,t){return!!e&&("TSImportEqualsDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSExternalModuleReference=function(e,t){return!!e&&("TSExternalModuleReference"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNonNullExpression=function(e,t){return!!e&&("TSNonNullExpression"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSExportAssignment=function(e,t){return!!e&&("TSExportAssignment"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSNamespaceExportDeclaration=function(e,t){return!!e&&("TSNamespaceExportDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeAnnotation=function(e,t){return!!e&&("TSTypeAnnotation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeParameterInstantiation=function(e,t){return!!e&&("TSTypeParameterInstantiation"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeParameterDeclaration=function(e,t){return!!e&&("TSTypeParameterDeclaration"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isTSTypeParameter=function(e,t){return!!e&&("TSTypeParameter"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isExpression=function(e,t){if(!e)return!1;const r=e.type;return("ArrayExpression"===r||"AssignmentExpression"===r||"BinaryExpression"===r||"CallExpression"===r||"ConditionalExpression"===r||"FunctionExpression"===r||"Identifier"===r||"StringLiteral"===r||"NumericLiteral"===r||"NullLiteral"===r||"BooleanLiteral"===r||"RegExpLiteral"===r||"LogicalExpression"===r||"MemberExpression"===r||"NewExpression"===r||"ObjectExpression"===r||"SequenceExpression"===r||"ParenthesizedExpression"===r||"ThisExpression"===r||"UnaryExpression"===r||"UpdateExpression"===r||"ArrowFunctionExpression"===r||"ClassExpression"===r||"MetaProperty"===r||"Super"===r||"TaggedTemplateExpression"===r||"TemplateLiteral"===r||"YieldExpression"===r||"AwaitExpression"===r||"Import"===r||"BigIntLiteral"===r||"OptionalMemberExpression"===r||"OptionalCallExpression"===r||"TypeCastExpression"===r||"JSXElement"===r||"JSXFragment"===r||"BindExpression"===r||"PipelinePrimaryTopicReference"===r||"DoExpression"===r||"RecordExpression"===r||"TupleExpression"===r||"DecimalLiteral"===r||"ModuleExpression"===r||"TSAsExpression"===r||"TSTypeAssertion"===r||"TSNonNullExpression"===r||"Placeholder"===r&&("Expression"===e.expectedNode||"Identifier"===e.expectedNode||"StringLiteral"===e.expectedNode))&&(void 0===t||(0,n.default)(e,t))},t.isBinary=function(e,t){if(!e)return!1;const r=e.type;return("BinaryExpression"===r||"LogicalExpression"===r)&&(void 0===t||(0,n.default)(e,t))},t.isScopable=function(e,t){if(!e)return!1;const r=e.type;return("BlockStatement"===r||"CatchClause"===r||"DoWhileStatement"===r||"ForInStatement"===r||"ForStatement"===r||"FunctionDeclaration"===r||"FunctionExpression"===r||"Program"===r||"ObjectMethod"===r||"SwitchStatement"===r||"WhileStatement"===r||"ArrowFunctionExpression"===r||"ClassExpression"===r||"ClassDeclaration"===r||"ForOfStatement"===r||"ClassMethod"===r||"ClassPrivateMethod"===r||"StaticBlock"===r||"TSModuleBlock"===r||"Placeholder"===r&&"BlockStatement"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isBlockParent=function(e,t){if(!e)return!1;const r=e.type;return("BlockStatement"===r||"CatchClause"===r||"DoWhileStatement"===r||"ForInStatement"===r||"ForStatement"===r||"FunctionDeclaration"===r||"FunctionExpression"===r||"Program"===r||"ObjectMethod"===r||"SwitchStatement"===r||"WhileStatement"===r||"ArrowFunctionExpression"===r||"ForOfStatement"===r||"ClassMethod"===r||"ClassPrivateMethod"===r||"StaticBlock"===r||"TSModuleBlock"===r||"Placeholder"===r&&"BlockStatement"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isBlock=function(e,t){if(!e)return!1;const r=e.type;return("BlockStatement"===r||"Program"===r||"TSModuleBlock"===r||"Placeholder"===r&&"BlockStatement"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isStatement=function(e,t){if(!e)return!1;const r=e.type;return("BlockStatement"===r||"BreakStatement"===r||"ContinueStatement"===r||"DebuggerStatement"===r||"DoWhileStatement"===r||"EmptyStatement"===r||"ExpressionStatement"===r||"ForInStatement"===r||"ForStatement"===r||"FunctionDeclaration"===r||"IfStatement"===r||"LabeledStatement"===r||"ReturnStatement"===r||"SwitchStatement"===r||"ThrowStatement"===r||"TryStatement"===r||"VariableDeclaration"===r||"WhileStatement"===r||"WithStatement"===r||"ClassDeclaration"===r||"ExportAllDeclaration"===r||"ExportDefaultDeclaration"===r||"ExportNamedDeclaration"===r||"ForOfStatement"===r||"ImportDeclaration"===r||"DeclareClass"===r||"DeclareFunction"===r||"DeclareInterface"===r||"DeclareModule"===r||"DeclareModuleExports"===r||"DeclareTypeAlias"===r||"DeclareOpaqueType"===r||"DeclareVariable"===r||"DeclareExportDeclaration"===r||"DeclareExportAllDeclaration"===r||"InterfaceDeclaration"===r||"OpaqueType"===r||"TypeAlias"===r||"EnumDeclaration"===r||"TSDeclareFunction"===r||"TSInterfaceDeclaration"===r||"TSTypeAliasDeclaration"===r||"TSEnumDeclaration"===r||"TSModuleDeclaration"===r||"TSImportEqualsDeclaration"===r||"TSExportAssignment"===r||"TSNamespaceExportDeclaration"===r||"Placeholder"===r&&("Statement"===e.expectedNode||"Declaration"===e.expectedNode||"BlockStatement"===e.expectedNode))&&(void 0===t||(0,n.default)(e,t))},t.isTerminatorless=function(e,t){if(!e)return!1;const r=e.type;return("BreakStatement"===r||"ContinueStatement"===r||"ReturnStatement"===r||"ThrowStatement"===r||"YieldExpression"===r||"AwaitExpression"===r)&&(void 0===t||(0,n.default)(e,t))},t.isCompletionStatement=function(e,t){if(!e)return!1;const r=e.type;return("BreakStatement"===r||"ContinueStatement"===r||"ReturnStatement"===r||"ThrowStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isConditional=function(e,t){if(!e)return!1;const r=e.type;return("ConditionalExpression"===r||"IfStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isLoop=function(e,t){if(!e)return!1;const r=e.type;return("DoWhileStatement"===r||"ForInStatement"===r||"ForStatement"===r||"WhileStatement"===r||"ForOfStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isWhile=function(e,t){if(!e)return!1;const r=e.type;return("DoWhileStatement"===r||"WhileStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isExpressionWrapper=function(e,t){if(!e)return!1;const r=e.type;return("ExpressionStatement"===r||"ParenthesizedExpression"===r||"TypeCastExpression"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFor=function(e,t){if(!e)return!1;const r=e.type;return("ForInStatement"===r||"ForStatement"===r||"ForOfStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isForXStatement=function(e,t){if(!e)return!1;const r=e.type;return("ForInStatement"===r||"ForOfStatement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFunction=function(e,t){if(!e)return!1;const r=e.type;return("FunctionDeclaration"===r||"FunctionExpression"===r||"ObjectMethod"===r||"ArrowFunctionExpression"===r||"ClassMethod"===r||"ClassPrivateMethod"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFunctionParent=function(e,t){if(!e)return!1;const r=e.type;return("FunctionDeclaration"===r||"FunctionExpression"===r||"ObjectMethod"===r||"ArrowFunctionExpression"===r||"ClassMethod"===r||"ClassPrivateMethod"===r)&&(void 0===t||(0,n.default)(e,t))},t.isPureish=function(e,t){if(!e)return!1;const r=e.type;return("FunctionDeclaration"===r||"FunctionExpression"===r||"StringLiteral"===r||"NumericLiteral"===r||"NullLiteral"===r||"BooleanLiteral"===r||"RegExpLiteral"===r||"ArrowFunctionExpression"===r||"BigIntLiteral"===r||"DecimalLiteral"===r||"Placeholder"===r&&"StringLiteral"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isDeclaration=function(e,t){if(!e)return!1;const r=e.type;return("FunctionDeclaration"===r||"VariableDeclaration"===r||"ClassDeclaration"===r||"ExportAllDeclaration"===r||"ExportDefaultDeclaration"===r||"ExportNamedDeclaration"===r||"ImportDeclaration"===r||"DeclareClass"===r||"DeclareFunction"===r||"DeclareInterface"===r||"DeclareModule"===r||"DeclareModuleExports"===r||"DeclareTypeAlias"===r||"DeclareOpaqueType"===r||"DeclareVariable"===r||"DeclareExportDeclaration"===r||"DeclareExportAllDeclaration"===r||"InterfaceDeclaration"===r||"OpaqueType"===r||"TypeAlias"===r||"EnumDeclaration"===r||"TSDeclareFunction"===r||"TSInterfaceDeclaration"===r||"TSTypeAliasDeclaration"===r||"TSEnumDeclaration"===r||"TSModuleDeclaration"===r||"Placeholder"===r&&"Declaration"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isPatternLike=function(e,t){if(!e)return!1;const r=e.type;return("Identifier"===r||"RestElement"===r||"AssignmentPattern"===r||"ArrayPattern"===r||"ObjectPattern"===r||"Placeholder"===r&&("Pattern"===e.expectedNode||"Identifier"===e.expectedNode))&&(void 0===t||(0,n.default)(e,t))},t.isLVal=function(e,t){if(!e)return!1;const r=e.type;return("Identifier"===r||"MemberExpression"===r||"RestElement"===r||"AssignmentPattern"===r||"ArrayPattern"===r||"ObjectPattern"===r||"TSParameterProperty"===r||"Placeholder"===r&&("Pattern"===e.expectedNode||"Identifier"===e.expectedNode))&&(void 0===t||(0,n.default)(e,t))},t.isTSEntityName=function(e,t){if(!e)return!1;const r=e.type;return("Identifier"===r||"TSQualifiedName"===r||"Placeholder"===r&&"Identifier"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isLiteral=function(e,t){if(!e)return!1;const r=e.type;return("StringLiteral"===r||"NumericLiteral"===r||"NullLiteral"===r||"BooleanLiteral"===r||"RegExpLiteral"===r||"TemplateLiteral"===r||"BigIntLiteral"===r||"DecimalLiteral"===r||"Placeholder"===r&&"StringLiteral"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isImmutable=function(e,t){if(!e)return!1;const r=e.type;return("StringLiteral"===r||"NumericLiteral"===r||"NullLiteral"===r||"BooleanLiteral"===r||"BigIntLiteral"===r||"JSXAttribute"===r||"JSXClosingElement"===r||"JSXElement"===r||"JSXExpressionContainer"===r||"JSXSpreadChild"===r||"JSXOpeningElement"===r||"JSXText"===r||"JSXFragment"===r||"JSXOpeningFragment"===r||"JSXClosingFragment"===r||"DecimalLiteral"===r||"Placeholder"===r&&"StringLiteral"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isUserWhitespacable=function(e,t){if(!e)return!1;const r=e.type;return("ObjectMethod"===r||"ObjectProperty"===r||"ObjectTypeInternalSlot"===r||"ObjectTypeCallProperty"===r||"ObjectTypeIndexer"===r||"ObjectTypeProperty"===r||"ObjectTypeSpreadProperty"===r)&&(void 0===t||(0,n.default)(e,t))},t.isMethod=function(e,t){if(!e)return!1;const r=e.type;return("ObjectMethod"===r||"ClassMethod"===r||"ClassPrivateMethod"===r)&&(void 0===t||(0,n.default)(e,t))},t.isObjectMember=function(e,t){if(!e)return!1;const r=e.type;return("ObjectMethod"===r||"ObjectProperty"===r)&&(void 0===t||(0,n.default)(e,t))},t.isProperty=function(e,t){if(!e)return!1;const r=e.type;return("ObjectProperty"===r||"ClassProperty"===r||"ClassPrivateProperty"===r)&&(void 0===t||(0,n.default)(e,t))},t.isUnaryLike=function(e,t){if(!e)return!1;const r=e.type;return("UnaryExpression"===r||"SpreadElement"===r)&&(void 0===t||(0,n.default)(e,t))},t.isPattern=function(e,t){if(!e)return!1;const r=e.type;return("AssignmentPattern"===r||"ArrayPattern"===r||"ObjectPattern"===r||"Placeholder"===r&&"Pattern"===e.expectedNode)&&(void 0===t||(0,n.default)(e,t))},t.isClass=function(e,t){if(!e)return!1;const r=e.type;return("ClassExpression"===r||"ClassDeclaration"===r)&&(void 0===t||(0,n.default)(e,t))},t.isModuleDeclaration=function(e,t){if(!e)return!1;const r=e.type;return("ExportAllDeclaration"===r||"ExportDefaultDeclaration"===r||"ExportNamedDeclaration"===r||"ImportDeclaration"===r)&&(void 0===t||(0,n.default)(e,t))},t.isExportDeclaration=function(e,t){if(!e)return!1;const r=e.type;return("ExportAllDeclaration"===r||"ExportDefaultDeclaration"===r||"ExportNamedDeclaration"===r)&&(void 0===t||(0,n.default)(e,t))},t.isModuleSpecifier=function(e,t){if(!e)return!1;const r=e.type;return("ExportSpecifier"===r||"ImportDefaultSpecifier"===r||"ImportNamespaceSpecifier"===r||"ImportSpecifier"===r||"ExportNamespaceSpecifier"===r||"ExportDefaultSpecifier"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFlow=function(e,t){if(!e)return!1;const r=e.type;return("AnyTypeAnnotation"===r||"ArrayTypeAnnotation"===r||"BooleanTypeAnnotation"===r||"BooleanLiteralTypeAnnotation"===r||"NullLiteralTypeAnnotation"===r||"ClassImplements"===r||"DeclareClass"===r||"DeclareFunction"===r||"DeclareInterface"===r||"DeclareModule"===r||"DeclareModuleExports"===r||"DeclareTypeAlias"===r||"DeclareOpaqueType"===r||"DeclareVariable"===r||"DeclareExportDeclaration"===r||"DeclareExportAllDeclaration"===r||"DeclaredPredicate"===r||"ExistsTypeAnnotation"===r||"FunctionTypeAnnotation"===r||"FunctionTypeParam"===r||"GenericTypeAnnotation"===r||"InferredPredicate"===r||"InterfaceExtends"===r||"InterfaceDeclaration"===r||"InterfaceTypeAnnotation"===r||"IntersectionTypeAnnotation"===r||"MixedTypeAnnotation"===r||"EmptyTypeAnnotation"===r||"NullableTypeAnnotation"===r||"NumberLiteralTypeAnnotation"===r||"NumberTypeAnnotation"===r||"ObjectTypeAnnotation"===r||"ObjectTypeInternalSlot"===r||"ObjectTypeCallProperty"===r||"ObjectTypeIndexer"===r||"ObjectTypeProperty"===r||"ObjectTypeSpreadProperty"===r||"OpaqueType"===r||"QualifiedTypeIdentifier"===r||"StringLiteralTypeAnnotation"===r||"StringTypeAnnotation"===r||"SymbolTypeAnnotation"===r||"ThisTypeAnnotation"===r||"TupleTypeAnnotation"===r||"TypeofTypeAnnotation"===r||"TypeAlias"===r||"TypeAnnotation"===r||"TypeCastExpression"===r||"TypeParameter"===r||"TypeParameterDeclaration"===r||"TypeParameterInstantiation"===r||"UnionTypeAnnotation"===r||"Variance"===r||"VoidTypeAnnotation"===r||"IndexedAccessType"===r||"OptionalIndexedAccessType"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFlowType=function(e,t){if(!e)return!1;const r=e.type;return("AnyTypeAnnotation"===r||"ArrayTypeAnnotation"===r||"BooleanTypeAnnotation"===r||"BooleanLiteralTypeAnnotation"===r||"NullLiteralTypeAnnotation"===r||"ExistsTypeAnnotation"===r||"FunctionTypeAnnotation"===r||"GenericTypeAnnotation"===r||"InterfaceTypeAnnotation"===r||"IntersectionTypeAnnotation"===r||"MixedTypeAnnotation"===r||"EmptyTypeAnnotation"===r||"NullableTypeAnnotation"===r||"NumberLiteralTypeAnnotation"===r||"NumberTypeAnnotation"===r||"ObjectTypeAnnotation"===r||"StringLiteralTypeAnnotation"===r||"StringTypeAnnotation"===r||"SymbolTypeAnnotation"===r||"ThisTypeAnnotation"===r||"TupleTypeAnnotation"===r||"TypeofTypeAnnotation"===r||"UnionTypeAnnotation"===r||"VoidTypeAnnotation"===r||"IndexedAccessType"===r||"OptionalIndexedAccessType"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFlowBaseAnnotation=function(e,t){if(!e)return!1;const r=e.type;return("AnyTypeAnnotation"===r||"BooleanTypeAnnotation"===r||"NullLiteralTypeAnnotation"===r||"MixedTypeAnnotation"===r||"EmptyTypeAnnotation"===r||"NumberTypeAnnotation"===r||"StringTypeAnnotation"===r||"SymbolTypeAnnotation"===r||"ThisTypeAnnotation"===r||"VoidTypeAnnotation"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFlowDeclaration=function(e,t){if(!e)return!1;const r=e.type;return("DeclareClass"===r||"DeclareFunction"===r||"DeclareInterface"===r||"DeclareModule"===r||"DeclareModuleExports"===r||"DeclareTypeAlias"===r||"DeclareOpaqueType"===r||"DeclareVariable"===r||"DeclareExportDeclaration"===r||"DeclareExportAllDeclaration"===r||"InterfaceDeclaration"===r||"OpaqueType"===r||"TypeAlias"===r)&&(void 0===t||(0,n.default)(e,t))},t.isFlowPredicate=function(e,t){if(!e)return!1;const r=e.type;return("DeclaredPredicate"===r||"InferredPredicate"===r)&&(void 0===t||(0,n.default)(e,t))},t.isEnumBody=function(e,t){if(!e)return!1;const r=e.type;return("EnumBooleanBody"===r||"EnumNumberBody"===r||"EnumStringBody"===r||"EnumSymbolBody"===r)&&(void 0===t||(0,n.default)(e,t))},t.isEnumMember=function(e,t){if(!e)return!1;const r=e.type;return("EnumBooleanMember"===r||"EnumNumberMember"===r||"EnumStringMember"===r||"EnumDefaultedMember"===r)&&(void 0===t||(0,n.default)(e,t))},t.isJSX=function(e,t){if(!e)return!1;const r=e.type;return("JSXAttribute"===r||"JSXClosingElement"===r||"JSXElement"===r||"JSXEmptyExpression"===r||"JSXExpressionContainer"===r||"JSXSpreadChild"===r||"JSXIdentifier"===r||"JSXMemberExpression"===r||"JSXNamespacedName"===r||"JSXOpeningElement"===r||"JSXSpreadAttribute"===r||"JSXText"===r||"JSXFragment"===r||"JSXOpeningFragment"===r||"JSXClosingFragment"===r)&&(void 0===t||(0,n.default)(e,t))},t.isPrivate=function(e,t){if(!e)return!1;const r=e.type;return("ClassPrivateProperty"===r||"ClassPrivateMethod"===r||"PrivateName"===r)&&(void 0===t||(0,n.default)(e,t))},t.isTSTypeElement=function(e,t){if(!e)return!1;const r=e.type;return("TSCallSignatureDeclaration"===r||"TSConstructSignatureDeclaration"===r||"TSPropertySignature"===r||"TSMethodSignature"===r||"TSIndexSignature"===r)&&(void 0===t||(0,n.default)(e,t))},t.isTSType=function(e,t){if(!e)return!1;const r=e.type;return("TSAnyKeyword"===r||"TSBooleanKeyword"===r||"TSBigIntKeyword"===r||"TSIntrinsicKeyword"===r||"TSNeverKeyword"===r||"TSNullKeyword"===r||"TSNumberKeyword"===r||"TSObjectKeyword"===r||"TSStringKeyword"===r||"TSSymbolKeyword"===r||"TSUndefinedKeyword"===r||"TSUnknownKeyword"===r||"TSVoidKeyword"===r||"TSThisType"===r||"TSFunctionType"===r||"TSConstructorType"===r||"TSTypeReference"===r||"TSTypePredicate"===r||"TSTypeQuery"===r||"TSTypeLiteral"===r||"TSArrayType"===r||"TSTupleType"===r||"TSOptionalType"===r||"TSRestType"===r||"TSUnionType"===r||"TSIntersectionType"===r||"TSConditionalType"===r||"TSInferType"===r||"TSParenthesizedType"===r||"TSTypeOperator"===r||"TSIndexedAccessType"===r||"TSMappedType"===r||"TSLiteralType"===r||"TSExpressionWithTypeArguments"===r||"TSImportType"===r)&&(void 0===t||(0,n.default)(e,t))},t.isTSBaseType=function(e,t){if(!e)return!1;const r=e.type;return("TSAnyKeyword"===r||"TSBooleanKeyword"===r||"TSBigIntKeyword"===r||"TSIntrinsicKeyword"===r||"TSNeverKeyword"===r||"TSNullKeyword"===r||"TSNumberKeyword"===r||"TSObjectKeyword"===r||"TSStringKeyword"===r||"TSSymbolKeyword"===r||"TSUndefinedKeyword"===r||"TSUnknownKeyword"===r||"TSVoidKeyword"===r||"TSThisType"===r||"TSLiteralType"===r)&&(void 0===t||(0,n.default)(e,t))},t.isNumberLiteral=function(e,t){return!!e&&("NumberLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isRegexLiteral=function(e,t){return!!e&&("RegexLiteral"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isRestProperty=function(e,t){return!!e&&("RestProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))},t.isSpreadProperty=function(e,t){return!!e&&("SpreadProperty"===e.type&&(void 0===t||(0,n.default)(e,t)))};var n=r(127)},(e,t,r)=>{var n=function(e){return e&&e.Math==Math&&e};e.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof r.g&&r.g)||function(){return this}()||Function("return this")()},(e,t,r)=>{const n=r(42),{MAX_LENGTH:s,MAX_SAFE_INTEGER:i}=r(41),{re:o,t:a}=r(23),l=r(43),{compareIdentifiers:c}=r(94);class u{constructor(e,t){if(t=l(t),e instanceof u){if(e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease)return e;e=e.version}else if("string"!=typeof e)throw new TypeError(`Invalid Version: ${e}`);if(e.length>s)throw new TypeError(`version is longer than ${s} characters`);n("SemVer",e,t),this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease;const r=e.trim().match(t.loose?o[a.LOOSE]:o[a.FULL]);if(!r)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+r[1],this.minor=+r[2],this.patch=+r[3],this.major>i||this.major<0)throw new TypeError("Invalid major version");if(this.minor>i||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>i||this.patch<0)throw new TypeError("Invalid patch version");r[4]?this.prerelease=r[4].split(".").map((e=>{if(/^[0-9]+$/.test(e)){const t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[e]&&(this.prerelease[e]++,e=-2);-1===e&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error(`invalid increment argument: ${e}`)}return this.format(),this.raw=this.version,this}}e.exports=u},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.declare=function(e){return(t,s,i)=>{var o;let a;for(const e of Object.keys(r)){var l;t[e]||(a=null!=(l=a)?l:n(t),a[e]=r[e](a))}return e(null!=(o=a)?o:t,s||{},i)}};const r={assertVersion:e=>t=>{!function(e,t){if("number"==typeof e){if(!Number.isInteger(e))throw new Error("Expected string or integer value.");e=`^${e}.0.0-0`}if("string"!=typeof e)throw new Error("Expected string or integer value.");const r=Error.stackTraceLimit;let n;throw"number"==typeof r&&r<25&&(Error.stackTraceLimit=25),n="7."===t.slice(0,2)?new Error(`Requires Babel "^7.0.0-beta.41", but was loaded with "${t}". You'll need to update your @babel/core version.`):new Error(`Requires Babel "${e}", but was loaded with "${t}". If you are sure you have a compatible version of @babel/core, it is likely that something in your build process is loading the wrong version. Inspect the stack trace of this error to look for the first entry that doesn't mention "@babel/core" or "babel-core" to see what is calling Babel.`),"number"==typeof r&&(Error.stackTraceLimit=r),Object.assign(n,{code:"BABEL_VERSION_UNSUPPORTED",version:t,range:e})}(t,e.version)},targets:()=>()=>({}),assumption:()=>()=>{}};function n(e){let t=null;return"string"==typeof e.version&&/^7\./.test(e.version)&&(t=Object.getPrototypeOf(e),!t||s(t,"version")&&s(t,"transform")&&s(t,"template")&&s(t,"types")||(t=null)),Object.assign({},t,e)}function s(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},(e,t)=>{"use strict";t.__esModule=!0,t.UNIVERSAL=t.ATTRIBUTE=t.CLASS=t.COMBINATOR=t.COMMENT=t.ID=t.NESTING=t.PSEUDO=t.ROOT=t.SELECTOR=t.STRING=t.TAG=void 0,t.TAG="tag",t.STRING="string",t.SELECTOR="selector",t.ROOT="root",t.PSEUDO="pseudo",t.NESTING="nesting",t.ID="id",t.COMMENT="comment",t.COMBINATOR="combinator",t.CLASS="class",t.ATTRIBUTE="attribute",t.UNIVERSAL="universal"},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.arrayExpression=function(e){return(0,n.default)("ArrayExpression",...arguments)},t.assignmentExpression=function(e,t,r){return(0,n.default)("AssignmentExpression",...arguments)},t.binaryExpression=function(e,t,r){return(0,n.default)("BinaryExpression",...arguments)},t.interpreterDirective=function(e){return(0,n.default)("InterpreterDirective",...arguments)},t.directive=function(e){return(0,n.default)("Directive",...arguments)},t.directiveLiteral=function(e){return(0,n.default)("DirectiveLiteral",...arguments)},t.blockStatement=function(e,t){return(0,n.default)("BlockStatement",...arguments)},t.breakStatement=function(e){return(0,n.default)("BreakStatement",...arguments)},t.callExpression=function(e,t){return(0,n.default)("CallExpression",...arguments)},t.catchClause=function(e,t){return(0,n.default)("CatchClause",...arguments)},t.conditionalExpression=function(e,t,r){return(0,n.default)("ConditionalExpression",...arguments)},t.continueStatement=function(e){return(0,n.default)("ContinueStatement",...arguments)},t.debuggerStatement=function(){return(0,n.default)("DebuggerStatement",...arguments)},t.doWhileStatement=function(e,t){return(0,n.default)("DoWhileStatement",...arguments)},t.emptyStatement=function(){return(0,n.default)("EmptyStatement",...arguments)},t.expressionStatement=function(e){return(0,n.default)("ExpressionStatement",...arguments)},t.file=function(e,t,r){return(0,n.default)("File",...arguments)},t.forInStatement=function(e,t,r){return(0,n.default)("ForInStatement",...arguments)},t.forStatement=function(e,t,r,s){return(0,n.default)("ForStatement",...arguments)},t.functionDeclaration=function(e,t,r,s,i){return(0,n.default)("FunctionDeclaration",...arguments)},t.functionExpression=function(e,t,r,s,i){return(0,n.default)("FunctionExpression",...arguments)},t.identifier=function(e){return(0,n.default)("Identifier",...arguments)},t.ifStatement=function(e,t,r){return(0,n.default)("IfStatement",...arguments)},t.labeledStatement=function(e,t){return(0,n.default)("LabeledStatement",...arguments)},t.stringLiteral=function(e){return(0,n.default)("StringLiteral",...arguments)},t.numericLiteral=function(e){return(0,n.default)("NumericLiteral",...arguments)},t.nullLiteral=function(){return(0,n.default)("NullLiteral",...arguments)},t.booleanLiteral=function(e){return(0,n.default)("BooleanLiteral",...arguments)},t.regExpLiteral=function(e,t){return(0,n.default)("RegExpLiteral",...arguments)},t.logicalExpression=function(e,t,r){return(0,n.default)("LogicalExpression",...arguments)},t.memberExpression=function(e,t,r,s){return(0,n.default)("MemberExpression",...arguments)},t.newExpression=function(e,t){return(0,n.default)("NewExpression",...arguments)},t.program=function(e,t,r,s){return(0,n.default)("Program",...arguments)},t.objectExpression=function(e){return(0,n.default)("ObjectExpression",...arguments)},t.objectMethod=function(e,t,r,s,i,o,a){return(0,n.default)("ObjectMethod",...arguments)},t.objectProperty=function(e,t,r,s,i){return(0,n.default)("ObjectProperty",...arguments)},t.restElement=function(e){return(0,n.default)("RestElement",...arguments)},t.returnStatement=function(e){return(0,n.default)("ReturnStatement",...arguments)},t.sequenceExpression=function(e){return(0,n.default)("SequenceExpression",...arguments)},t.parenthesizedExpression=function(e){return(0,n.default)("ParenthesizedExpression",...arguments)},t.switchCase=function(e,t){return(0,n.default)("SwitchCase",...arguments)},t.switchStatement=function(e,t){return(0,n.default)("SwitchStatement",...arguments)},t.thisExpression=function(){return(0,n.default)("ThisExpression",...arguments)},t.throwStatement=function(e){return(0,n.default)("ThrowStatement",...arguments)},t.tryStatement=function(e,t,r){return(0,n.default)("TryStatement",...arguments)},t.unaryExpression=function(e,t,r){return(0,n.default)("UnaryExpression",...arguments)},t.updateExpression=function(e,t,r){return(0,n.default)("UpdateExpression",...arguments)},t.variableDeclaration=function(e,t){return(0,n.default)("VariableDeclaration",...arguments)},t.variableDeclarator=function(e,t){return(0,n.default)("VariableDeclarator",...arguments)},t.whileStatement=function(e,t){return(0,n.default)("WhileStatement",...arguments)},t.withStatement=function(e,t){return(0,n.default)("WithStatement",...arguments)},t.assignmentPattern=function(e,t){return(0,n.default)("AssignmentPattern",...arguments)},t.arrayPattern=function(e){return(0,n.default)("ArrayPattern",...arguments)},t.arrowFunctionExpression=function(e,t,r){return(0,n.default)("ArrowFunctionExpression",...arguments)},t.classBody=function(e){return(0,n.default)("ClassBody",...arguments)},t.classExpression=function(e,t,r,s){return(0,n.default)("ClassExpression",...arguments)},t.classDeclaration=function(e,t,r,s){return(0,n.default)("ClassDeclaration",...arguments)},t.exportAllDeclaration=function(e){return(0,n.default)("ExportAllDeclaration",...arguments)},t.exportDefaultDeclaration=function(e){return(0,n.default)("ExportDefaultDeclaration",...arguments)},t.exportNamedDeclaration=function(e,t,r){return(0,n.default)("ExportNamedDeclaration",...arguments)},t.exportSpecifier=function(e,t){return(0,n.default)("ExportSpecifier",...arguments)},t.forOfStatement=function(e,t,r,s){return(0,n.default)("ForOfStatement",...arguments)},t.importDeclaration=function(e,t){return(0,n.default)("ImportDeclaration",...arguments)},t.importDefaultSpecifier=function(e){return(0,n.default)("ImportDefaultSpecifier",...arguments)},t.importNamespaceSpecifier=function(e){return(0,n.default)("ImportNamespaceSpecifier",...arguments)},t.importSpecifier=function(e,t){return(0,n.default)("ImportSpecifier",...arguments)},t.metaProperty=function(e,t){return(0,n.default)("MetaProperty",...arguments)},t.classMethod=function(e,t,r,s,i,o,a,l){return(0,n.default)("ClassMethod",...arguments)},t.objectPattern=function(e){return(0,n.default)("ObjectPattern",...arguments)},t.spreadElement=function(e){return(0,n.default)("SpreadElement",...arguments)},t.super=function(){return(0,n.default)("Super",...arguments)},t.taggedTemplateExpression=function(e,t){return(0,n.default)("TaggedTemplateExpression",...arguments)},t.templateElement=function(e,t){return(0,n.default)("TemplateElement",...arguments)},t.templateLiteral=function(e,t){return(0,n.default)("TemplateLiteral",...arguments)},t.yieldExpression=function(e,t){return(0,n.default)("YieldExpression",...arguments)},t.awaitExpression=function(e){return(0,n.default)("AwaitExpression",...arguments)},t.import=function(){return(0,n.default)("Import",...arguments)},t.bigIntLiteral=function(e){return(0,n.default)("BigIntLiteral",...arguments)},t.exportNamespaceSpecifier=function(e){return(0,n.default)("ExportNamespaceSpecifier",...arguments)},t.optionalMemberExpression=function(e,t,r,s){return(0,n.default)("OptionalMemberExpression",...arguments)},t.optionalCallExpression=function(e,t,r){return(0,n.default)("OptionalCallExpression",...arguments)},t.anyTypeAnnotation=function(){return(0,n.default)("AnyTypeAnnotation",...arguments)},t.arrayTypeAnnotation=function(e){return(0,n.default)("ArrayTypeAnnotation",...arguments)},t.booleanTypeAnnotation=function(){return(0,n.default)("BooleanTypeAnnotation",...arguments)},t.booleanLiteralTypeAnnotation=function(e){return(0,n.default)("BooleanLiteralTypeAnnotation",...arguments)},t.nullLiteralTypeAnnotation=function(){return(0,n.default)("NullLiteralTypeAnnotation",...arguments)},t.classImplements=function(e,t){return(0,n.default)("ClassImplements",...arguments)},t.declareClass=function(e,t,r,s){return(0,n.default)("DeclareClass",...arguments)},t.declareFunction=function(e){return(0,n.default)("DeclareFunction",...arguments)},t.declareInterface=function(e,t,r,s){return(0,n.default)("DeclareInterface",...arguments)},t.declareModule=function(e,t,r){return(0,n.default)("DeclareModule",...arguments)},t.declareModuleExports=function(e){return(0,n.default)("DeclareModuleExports",...arguments)},t.declareTypeAlias=function(e,t,r){return(0,n.default)("DeclareTypeAlias",...arguments)},t.declareOpaqueType=function(e,t,r){return(0,n.default)("DeclareOpaqueType",...arguments)},t.declareVariable=function(e){return(0,n.default)("DeclareVariable",...arguments)},t.declareExportDeclaration=function(e,t,r){return(0,n.default)("DeclareExportDeclaration",...arguments)},t.declareExportAllDeclaration=function(e){return(0,n.default)("DeclareExportAllDeclaration",...arguments)},t.declaredPredicate=function(e){return(0,n.default)("DeclaredPredicate",...arguments)},t.existsTypeAnnotation=function(){return(0,n.default)("ExistsTypeAnnotation",...arguments)},t.functionTypeAnnotation=function(e,t,r,s){return(0,n.default)("FunctionTypeAnnotation",...arguments)},t.functionTypeParam=function(e,t){return(0,n.default)("FunctionTypeParam",...arguments)},t.genericTypeAnnotation=function(e,t){return(0,n.default)("GenericTypeAnnotation",...arguments)},t.inferredPredicate=function(){return(0,n.default)("InferredPredicate",...arguments)},t.interfaceExtends=function(e,t){return(0,n.default)("InterfaceExtends",...arguments)},t.interfaceDeclaration=function(e,t,r,s){return(0,n.default)("InterfaceDeclaration",...arguments)},t.interfaceTypeAnnotation=function(e,t){return(0,n.default)("InterfaceTypeAnnotation",...arguments)},t.intersectionTypeAnnotation=function(e){return(0,n.default)("IntersectionTypeAnnotation",...arguments)},t.mixedTypeAnnotation=function(){return(0,n.default)("MixedTypeAnnotation",...arguments)},t.emptyTypeAnnotation=function(){return(0,n.default)("EmptyTypeAnnotation",...arguments)},t.nullableTypeAnnotation=function(e){return(0,n.default)("NullableTypeAnnotation",...arguments)},t.numberLiteralTypeAnnotation=function(e){return(0,n.default)("NumberLiteralTypeAnnotation",...arguments)},t.numberTypeAnnotation=function(){return(0,n.default)("NumberTypeAnnotation",...arguments)},t.objectTypeAnnotation=function(e,t,r,s,i){return(0,n.default)("ObjectTypeAnnotation",...arguments)},t.objectTypeInternalSlot=function(e,t,r,s,i){return(0,n.default)("ObjectTypeInternalSlot",...arguments)},t.objectTypeCallProperty=function(e){return(0,n.default)("ObjectTypeCallProperty",...arguments)},t.objectTypeIndexer=function(e,t,r,s){return(0,n.default)("ObjectTypeIndexer",...arguments)},t.objectTypeProperty=function(e,t,r){return(0,n.default)("ObjectTypeProperty",...arguments)},t.objectTypeSpreadProperty=function(e){return(0,n.default)("ObjectTypeSpreadProperty",...arguments)},t.opaqueType=function(e,t,r,s){return(0,n.default)("OpaqueType",...arguments)},t.qualifiedTypeIdentifier=function(e,t){return(0,n.default)("QualifiedTypeIdentifier",...arguments)},t.stringLiteralTypeAnnotation=function(e){return(0,n.default)("StringLiteralTypeAnnotation",...arguments)},t.stringTypeAnnotation=function(){return(0,n.default)("StringTypeAnnotation",...arguments)},t.symbolTypeAnnotation=function(){return(0,n.default)("SymbolTypeAnnotation",...arguments)},t.thisTypeAnnotation=function(){return(0,n.default)("ThisTypeAnnotation",...arguments)},t.tupleTypeAnnotation=function(e){return(0,n.default)("TupleTypeAnnotation",...arguments)},t.typeofTypeAnnotation=function(e){return(0,n.default)("TypeofTypeAnnotation",...arguments)},t.typeAlias=function(e,t,r){return(0,n.default)("TypeAlias",...arguments)},t.typeAnnotation=function(e){return(0,n.default)("TypeAnnotation",...arguments)},t.typeCastExpression=function(e,t){return(0,n.default)("TypeCastExpression",...arguments)},t.typeParameter=function(e,t,r){return(0,n.default)("TypeParameter",...arguments)},t.typeParameterDeclaration=function(e){return(0,n.default)("TypeParameterDeclaration",...arguments)},t.typeParameterInstantiation=function(e){return(0,n.default)("TypeParameterInstantiation",...arguments)},t.unionTypeAnnotation=function(e){return(0,n.default)("UnionTypeAnnotation",...arguments)},t.variance=function(e){return(0,n.default)("Variance",...arguments)},t.voidTypeAnnotation=function(){return(0,n.default)("VoidTypeAnnotation",...arguments)},t.enumDeclaration=function(e,t){return(0,n.default)("EnumDeclaration",...arguments)},t.enumBooleanBody=function(e){return(0,n.default)("EnumBooleanBody",...arguments)},t.enumNumberBody=function(e){return(0,n.default)("EnumNumberBody",...arguments)},t.enumStringBody=function(e){return(0,n.default)("EnumStringBody",...arguments)},t.enumSymbolBody=function(e){return(0,n.default)("EnumSymbolBody",...arguments)},t.enumBooleanMember=function(e){return(0,n.default)("EnumBooleanMember",...arguments)},t.enumNumberMember=function(e,t){return(0,n.default)("EnumNumberMember",...arguments)},t.enumStringMember=function(e,t){return(0,n.default)("EnumStringMember",...arguments)},t.enumDefaultedMember=function(e){return(0,n.default)("EnumDefaultedMember",...arguments)},t.indexedAccessType=function(e,t){return(0,n.default)("IndexedAccessType",...arguments)},t.optionalIndexedAccessType=function(e,t){return(0,n.default)("OptionalIndexedAccessType",...arguments)},t.jSXAttribute=t.jsxAttribute=function(e,t){return(0,n.default)("JSXAttribute",...arguments)},t.jSXClosingElement=t.jsxClosingElement=function(e){return(0,n.default)("JSXClosingElement",...arguments)},t.jSXElement=t.jsxElement=function(e,t,r,s){return(0,n.default)("JSXElement",...arguments)},t.jSXEmptyExpression=t.jsxEmptyExpression=function(){return(0,n.default)("JSXEmptyExpression",...arguments)},t.jSXExpressionContainer=t.jsxExpressionContainer=function(e){return(0,n.default)("JSXExpressionContainer",...arguments)},t.jSXSpreadChild=t.jsxSpreadChild=function(e){return(0,n.default)("JSXSpreadChild",...arguments)},t.jSXIdentifier=t.jsxIdentifier=function(e){return(0,n.default)("JSXIdentifier",...arguments)},t.jSXMemberExpression=t.jsxMemberExpression=function(e,t){return(0,n.default)("JSXMemberExpression",...arguments)},t.jSXNamespacedName=t.jsxNamespacedName=function(e,t){return(0,n.default)("JSXNamespacedName",...arguments)},t.jSXOpeningElement=t.jsxOpeningElement=function(e,t,r){return(0,n.default)("JSXOpeningElement",...arguments)},t.jSXSpreadAttribute=t.jsxSpreadAttribute=function(e){return(0,n.default)("JSXSpreadAttribute",...arguments)},t.jSXText=t.jsxText=function(e){return(0,n.default)("JSXText",...arguments)},t.jSXFragment=t.jsxFragment=function(e,t,r){return(0,n.default)("JSXFragment",...arguments)},t.jSXOpeningFragment=t.jsxOpeningFragment=function(){return(0,n.default)("JSXOpeningFragment",...arguments)},t.jSXClosingFragment=t.jsxClosingFragment=function(){return(0,n.default)("JSXClosingFragment",...arguments)},t.noop=function(){return(0,n.default)("Noop",...arguments)},t.placeholder=function(e,t){return(0,n.default)("Placeholder",...arguments)},t.v8IntrinsicIdentifier=function(e){return(0,n.default)("V8IntrinsicIdentifier",...arguments)},t.argumentPlaceholder=function(){return(0,n.default)("ArgumentPlaceholder",...arguments)},t.bindExpression=function(e,t){return(0,n.default)("BindExpression",...arguments)},t.classProperty=function(e,t,r,s,i,o){return(0,n.default)("ClassProperty",...arguments)},t.pipelineTopicExpression=function(e){return(0,n.default)("PipelineTopicExpression",...arguments)},t.pipelineBareFunction=function(e){return(0,n.default)("PipelineBareFunction",...arguments)},t.pipelinePrimaryTopicReference=function(){return(0,n.default)("PipelinePrimaryTopicReference",...arguments)},t.classPrivateProperty=function(e,t,r,s){return(0,n.default)("ClassPrivateProperty",...arguments)},t.classPrivateMethod=function(e,t,r,s,i){return(0,n.default)("ClassPrivateMethod",...arguments)},t.importAttribute=function(e,t){return(0,n.default)("ImportAttribute",...arguments)},t.decorator=function(e){return(0,n.default)("Decorator",...arguments)},t.doExpression=function(e,t){return(0,n.default)("DoExpression",...arguments)},t.exportDefaultSpecifier=function(e){return(0,n.default)("ExportDefaultSpecifier",...arguments)},t.privateName=function(e){return(0,n.default)("PrivateName",...arguments)},t.recordExpression=function(e){return(0,n.default)("RecordExpression",...arguments)},t.tupleExpression=function(e){return(0,n.default)("TupleExpression",...arguments)},t.decimalLiteral=function(e){return(0,n.default)("DecimalLiteral",...arguments)},t.staticBlock=function(e){return(0,n.default)("StaticBlock",...arguments)},t.moduleExpression=function(e){return(0,n.default)("ModuleExpression",...arguments)},t.tSParameterProperty=t.tsParameterProperty=function(e){return(0,n.default)("TSParameterProperty",...arguments)},t.tSDeclareFunction=t.tsDeclareFunction=function(e,t,r,s){return(0,n.default)("TSDeclareFunction",...arguments)},t.tSDeclareMethod=t.tsDeclareMethod=function(e,t,r,s,i){return(0,n.default)("TSDeclareMethod",...arguments)},t.tSQualifiedName=t.tsQualifiedName=function(e,t){return(0,n.default)("TSQualifiedName",...arguments)},t.tSCallSignatureDeclaration=t.tsCallSignatureDeclaration=function(e,t,r){return(0,n.default)("TSCallSignatureDeclaration",...arguments)},t.tSConstructSignatureDeclaration=t.tsConstructSignatureDeclaration=function(e,t,r){return(0,n.default)("TSConstructSignatureDeclaration",...arguments)},t.tSPropertySignature=t.tsPropertySignature=function(e,t,r){return(0,n.default)("TSPropertySignature",...arguments)},t.tSMethodSignature=t.tsMethodSignature=function(e,t,r,s){return(0,n.default)("TSMethodSignature",...arguments)},t.tSIndexSignature=t.tsIndexSignature=function(e,t){return(0,n.default)("TSIndexSignature",...arguments)},t.tSAnyKeyword=t.tsAnyKeyword=function(){return(0,n.default)("TSAnyKeyword",...arguments)},t.tSBooleanKeyword=t.tsBooleanKeyword=function(){return(0,n.default)("TSBooleanKeyword",...arguments)},t.tSBigIntKeyword=t.tsBigIntKeyword=function(){return(0,n.default)("TSBigIntKeyword",...arguments)},t.tSIntrinsicKeyword=t.tsIntrinsicKeyword=function(){return(0,n.default)("TSIntrinsicKeyword",...arguments)},t.tSNeverKeyword=t.tsNeverKeyword=function(){return(0,n.default)("TSNeverKeyword",...arguments)},t.tSNullKeyword=t.tsNullKeyword=function(){return(0,n.default)("TSNullKeyword",...arguments)},t.tSNumberKeyword=t.tsNumberKeyword=function(){return(0,n.default)("TSNumberKeyword",...arguments)},t.tSObjectKeyword=t.tsObjectKeyword=function(){return(0,n.default)("TSObjectKeyword",...arguments)},t.tSStringKeyword=t.tsStringKeyword=function(){return(0,n.default)("TSStringKeyword",...arguments)},t.tSSymbolKeyword=t.tsSymbolKeyword=function(){return(0,n.default)("TSSymbolKeyword",...arguments)},t.tSUndefinedKeyword=t.tsUndefinedKeyword=function(){return(0,n.default)("TSUndefinedKeyword",...arguments)},t.tSUnknownKeyword=t.tsUnknownKeyword=function(){return(0,n.default)("TSUnknownKeyword",...arguments)},t.tSVoidKeyword=t.tsVoidKeyword=function(){return(0,n.default)("TSVoidKeyword",...arguments)},t.tSThisType=t.tsThisType=function(){return(0,n.default)("TSThisType",...arguments)},t.tSFunctionType=t.tsFunctionType=function(e,t,r){return(0,n.default)("TSFunctionType",...arguments)},t.tSConstructorType=t.tsConstructorType=function(e,t,r){return(0,n.default)("TSConstructorType",...arguments)},t.tSTypeReference=t.tsTypeReference=function(e,t){return(0,n.default)("TSTypeReference",...arguments)},t.tSTypePredicate=t.tsTypePredicate=function(e,t,r){return(0,n.default)("TSTypePredicate",...arguments)},t.tSTypeQuery=t.tsTypeQuery=function(e){return(0,n.default)("TSTypeQuery",...arguments)},t.tSTypeLiteral=t.tsTypeLiteral=function(e){return(0,n.default)("TSTypeLiteral",...arguments)},t.tSArrayType=t.tsArrayType=function(e){return(0,n.default)("TSArrayType",...arguments)},t.tSTupleType=t.tsTupleType=function(e){return(0,n.default)("TSTupleType",...arguments)},t.tSOptionalType=t.tsOptionalType=function(e){return(0,n.default)("TSOptionalType",...arguments)},t.tSRestType=t.tsRestType=function(e){return(0,n.default)("TSRestType",...arguments)},t.tSNamedTupleMember=t.tsNamedTupleMember=function(e,t,r){return(0,n.default)("TSNamedTupleMember",...arguments)},t.tSUnionType=t.tsUnionType=function(e){return(0,n.default)("TSUnionType",...arguments)},t.tSIntersectionType=t.tsIntersectionType=function(e){return(0,n.default)("TSIntersectionType",...arguments)},t.tSConditionalType=t.tsConditionalType=function(e,t,r,s){return(0,n.default)("TSConditionalType",...arguments)},t.tSInferType=t.tsInferType=function(e){return(0,n.default)("TSInferType",...arguments)},t.tSParenthesizedType=t.tsParenthesizedType=function(e){return(0,n.default)("TSParenthesizedType",...arguments)},t.tSTypeOperator=t.tsTypeOperator=function(e){return(0,n.default)("TSTypeOperator",...arguments)},t.tSIndexedAccessType=t.tsIndexedAccessType=function(e,t){return(0,n.default)("TSIndexedAccessType",...arguments)},t.tSMappedType=t.tsMappedType=function(e,t,r){return(0,n.default)("TSMappedType",...arguments)},t.tSLiteralType=t.tsLiteralType=function(e){return(0,n.default)("TSLiteralType",...arguments)},t.tSExpressionWithTypeArguments=t.tsExpressionWithTypeArguments=function(e,t){return(0,n.default)("TSExpressionWithTypeArguments",...arguments)},t.tSInterfaceDeclaration=t.tsInterfaceDeclaration=function(e,t,r,s){return(0,n.default)("TSInterfaceDeclaration",...arguments)},t.tSInterfaceBody=t.tsInterfaceBody=function(e){return(0,n.default)("TSInterfaceBody",...arguments)},t.tSTypeAliasDeclaration=t.tsTypeAliasDeclaration=function(e,t,r){return(0,n.default)("TSTypeAliasDeclaration",...arguments)},t.tSAsExpression=t.tsAsExpression=function(e,t){return(0,n.default)("TSAsExpression",...arguments)},t.tSTypeAssertion=t.tsTypeAssertion=function(e,t){return(0,n.default)("TSTypeAssertion",...arguments)},t.tSEnumDeclaration=t.tsEnumDeclaration=function(e,t){return(0,n.default)("TSEnumDeclaration",...arguments)},t.tSEnumMember=t.tsEnumMember=function(e,t){return(0,n.default)("TSEnumMember",...arguments)},t.tSModuleDeclaration=t.tsModuleDeclaration=function(e,t){return(0,n.default)("TSModuleDeclaration",...arguments)},t.tSModuleBlock=t.tsModuleBlock=function(e){return(0,n.default)("TSModuleBlock",...arguments)},t.tSImportType=t.tsImportType=function(e,t,r){return(0,n.default)("TSImportType",...arguments)},t.tSImportEqualsDeclaration=t.tsImportEqualsDeclaration=function(e,t){return(0,n.default)("TSImportEqualsDeclaration",...arguments)},t.tSExternalModuleReference=t.tsExternalModuleReference=function(e){return(0,n.default)("TSExternalModuleReference",...arguments)},t.tSNonNullExpression=t.tsNonNullExpression=function(e){return(0,n.default)("TSNonNullExpression",...arguments)},t.tSExportAssignment=t.tsExportAssignment=function(e){return(0,n.default)("TSExportAssignment",...arguments)},t.tSNamespaceExportDeclaration=t.tsNamespaceExportDeclaration=function(e){return(0,n.default)("TSNamespaceExportDeclaration",...arguments)},t.tSTypeAnnotation=t.tsTypeAnnotation=function(e){return(0,n.default)("TSTypeAnnotation",...arguments)},t.tSTypeParameterInstantiation=t.tsTypeParameterInstantiation=function(e){return(0,n.default)("TSTypeParameterInstantiation",...arguments)},t.tSTypeParameterDeclaration=t.tsTypeParameterDeclaration=function(e){return(0,n.default)("TSTypeParameterDeclaration",...arguments)},t.tSTypeParameter=t.tsTypeParameter=function(e,t,r){return(0,n.default)("TSTypeParameter",...arguments)},t.numberLiteral=function(...e){return(0,n.default)("NumberLiteral",...e)},t.regexLiteral=function(...e){return(0,n.default)("RegexLiteral",...e)},t.restProperty=function(...e){return(0,n.default)("RestProperty",...e)},t.spreadProperty=function(...e){return(0,n.default)("SpreadProperty",...e)};var n=r(367)},e=>{var t,r,n=e.exports={};function s(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function o(e){if(t===setTimeout)return setTimeout(e,0);if((t===s||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(r){try{return t.call(null,e,0)}catch(r){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:s}catch(e){t=s}try{r="function"==typeof clearTimeout?clearTimeout:i}catch(e){r=i}}();var a,l=[],c=!1,u=-1;function p(){c&&a&&(c=!1,a.length?l=a.concat(l):u=-1,l.length&&f())}function f(){if(!c){var e=o(p);c=!0;for(var t=l.length;t;){for(a=l,l=[];++u1)for(var r=1;r{"use strict";var n=r(7);function s(e){if("string"!=typeof e)throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function i(e,t){for(var r,n="",s=0,i=-1,o=0,a=0;a<=e.length;++a){if(a2){var l=n.lastIndexOf("/");if(l!==n.length-1){-1===l?(n="",s=0):s=(n=n.slice(0,l)).length-1-n.lastIndexOf("/"),i=a,o=0;continue}}else if(2===n.length||1===n.length){n="",s=0,i=a,o=0;continue}t&&(n.length>0?n+="/..":n="..",s=2)}else n.length>0?n+="/"+e.slice(i+1,a):n=e.slice(i+1,a),s=a-i-1;i=a,o=0}else 46===r&&-1!==o?++o:o=-1}return n}var o={resolve:function(){for(var e,t="",r=!1,o=arguments.length-1;o>=-1&&!r;o--){var a;o>=0?a=arguments[o]:(void 0===e&&(e=n.cwd()),a=e),s(a),0!==a.length&&(t=a+"/"+t,r=47===a.charCodeAt(0))}return t=i(t,!r),r?t.length>0?"/"+t:"/":t.length>0?t:"."},normalize:function(e){if(s(e),0===e.length)return".";var t=47===e.charCodeAt(0),r=47===e.charCodeAt(e.length-1);return 0!==(e=i(e,!t)).length||t||(e="."),e.length>0&&r&&(e+="/"),t?"/"+e:e},isAbsolute:function(e){return s(e),e.length>0&&47===e.charCodeAt(0)},join:function(){if(0===arguments.length)return".";for(var e,t=0;t0&&(void 0===e?e=r:e+="/"+r)}return void 0===e?".":o.normalize(e)},relative:function(e,t){if(s(e),s(t),e===t)return"";if((e=o.resolve(e))===(t=o.resolve(t)))return"";for(var r=1;rc){if(47===t.charCodeAt(a+p))return t.slice(a+p+1);if(0===p)return t.slice(a+p)}else i>c&&(47===e.charCodeAt(r+p)?u=p:0===p&&(u=0));break}var f=e.charCodeAt(r+p);if(f!==t.charCodeAt(a+p))break;47===f&&(u=p)}var d="";for(p=r+u+1;p<=n;++p)p!==n&&47!==e.charCodeAt(p)||(0===d.length?d+="..":d+="/..");return d.length>0?d+t.slice(a+u):(a+=u,47===t.charCodeAt(a)&&++a,t.slice(a))},_makeLong:function(e){return e},dirname:function(e){if(s(e),0===e.length)return".";for(var t=e.charCodeAt(0),r=47===t,n=-1,i=!0,o=e.length-1;o>=1;--o)if(47===(t=e.charCodeAt(o))){if(!i){n=o;break}}else i=!1;return-1===n?r?"/":".":r&&1===n?"//":e.slice(0,n)},basename:function(e,t){if(void 0!==t&&"string"!=typeof t)throw new TypeError('"ext" argument must be a string');s(e);var r,n=0,i=-1,o=!0;if(void 0!==t&&t.length>0&&t.length<=e.length){if(t.length===e.length&&t===e)return"";var a=t.length-1,l=-1;for(r=e.length-1;r>=0;--r){var c=e.charCodeAt(r);if(47===c){if(!o){n=r+1;break}}else-1===l&&(o=!1,l=r+1),a>=0&&(c===t.charCodeAt(a)?-1==--a&&(i=r):(a=-1,i=l))}return n===i?i=l:-1===i&&(i=e.length),e.slice(n,i)}for(r=e.length-1;r>=0;--r)if(47===e.charCodeAt(r)){if(!o){n=r+1;break}}else-1===i&&(o=!1,i=r+1);return-1===i?"":e.slice(n,i)},extname:function(e){s(e);for(var t=-1,r=0,n=-1,i=!0,o=0,a=e.length-1;a>=0;--a){var l=e.charCodeAt(a);if(47!==l)-1===n&&(i=!1,n=a+1),46===l?-1===t?t=a:1!==o&&(o=1):-1!==t&&(o=-1);else if(!i){r=a+1;break}}return-1===t||-1===n||0===o||1===o&&t===n-1&&t===r+1?"":e.slice(t,n)},format:function(e){if(null===e||"object"!=typeof e)throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof e);return function(e,t){var r=t.dir||t.root,n=t.base||(t.name||"")+(t.ext||"");return r?r===t.root?r+n:r+"/"+n:n}(0,e)},parse:function(e){s(e);var t={root:"",dir:"",base:"",ext:"",name:""};if(0===e.length)return t;var r,n=e.charCodeAt(0),i=47===n;i?(t.root="/",r=1):r=0;for(var o=-1,a=0,l=-1,c=!0,u=e.length-1,p=0;u>=r;--u)if(47!==(n=e.charCodeAt(u)))-1===l&&(c=!1,l=u+1),46===n?-1===o?o=u:1!==p&&(p=1):-1!==o&&(p=-1);else if(!c){a=u+1;break}return-1===o||-1===l||0===p||1===p&&o===l-1&&o===a+1?-1!==l&&(t.base=t.name=0===a&&i?e.slice(1,l):e.slice(a,l)):(0===a&&i?(t.name=e.slice(1,o),t.base=e.slice(1,l)):(t.name=e.slice(a,o),t.base=e.slice(a,l)),t.ext=e.slice(o,l)),a>0?t.dir=e.slice(0,a-1):i&&(t.dir="/"),t},sep:"/",delimiter:":",win32:null,posix:null};o.posix=o,e.exports=o},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Plugin=function(e){throw new Error(`The (${e}) Babel 5 plugin is being run with an unsupported Babel version.`)},Object.defineProperty(t,"File",{enumerable:!0,get:function(){return n.default}}),Object.defineProperty(t,"buildExternalHelpers",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"resolvePlugin",{enumerable:!0,get:function(){return i.resolvePlugin}}),Object.defineProperty(t,"resolvePreset",{enumerable:!0,get:function(){return i.resolvePreset}}),Object.defineProperty(t,"getEnv",{enumerable:!0,get:function(){return o.getEnv}}),Object.defineProperty(t,"tokTypes",{enumerable:!0,get:function(){return l().tokTypes}}),Object.defineProperty(t,"traverse",{enumerable:!0,get:function(){return c().default}}),Object.defineProperty(t,"template",{enumerable:!0,get:function(){return u().default}}),Object.defineProperty(t,"createConfigItem",{enumerable:!0,get:function(){return p.createConfigItem}}),Object.defineProperty(t,"createConfigItemSync",{enumerable:!0,get:function(){return p.createConfigItemSync}}),Object.defineProperty(t,"createConfigItemAsync",{enumerable:!0,get:function(){return p.createConfigItemAsync}}),Object.defineProperty(t,"loadPartialConfig",{enumerable:!0,get:function(){return p.loadPartialConfig}}),Object.defineProperty(t,"loadPartialConfigSync",{enumerable:!0,get:function(){return p.loadPartialConfigSync}}),Object.defineProperty(t,"loadPartialConfigAsync",{enumerable:!0,get:function(){return p.loadPartialConfigAsync}}),Object.defineProperty(t,"loadOptions",{enumerable:!0,get:function(){return p.loadOptions}}),Object.defineProperty(t,"loadOptionsSync",{enumerable:!0,get:function(){return p.loadOptionsSync}}),Object.defineProperty(t,"loadOptionsAsync",{enumerable:!0,get:function(){return p.loadOptionsAsync}}),Object.defineProperty(t,"transform",{enumerable:!0,get:function(){return f.transform}}),Object.defineProperty(t,"transformSync",{enumerable:!0,get:function(){return f.transformSync}}),Object.defineProperty(t,"transformAsync",{enumerable:!0,get:function(){return f.transformAsync}}),Object.defineProperty(t,"transformFile",{enumerable:!0,get:function(){return d.transformFile}}),Object.defineProperty(t,"transformFileSync",{enumerable:!0,get:function(){return d.transformFileSync}}),Object.defineProperty(t,"transformFileAsync",{enumerable:!0,get:function(){return d.transformFileAsync}}),Object.defineProperty(t,"transformFromAst",{enumerable:!0,get:function(){return h.transformFromAst}}),Object.defineProperty(t,"transformFromAstSync",{enumerable:!0,get:function(){return h.transformFromAstSync}}),Object.defineProperty(t,"transformFromAstAsync",{enumerable:!0,get:function(){return h.transformFromAstAsync}}),Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return m.parse}}),Object.defineProperty(t,"parseSync",{enumerable:!0,get:function(){return m.parseSync}}),Object.defineProperty(t,"parseAsync",{enumerable:!0,get:function(){return m.parseAsync}}),t.types=t.OptionManager=t.DEFAULT_EXTENSIONS=t.version=void 0;var n=r(126),s=r(465),i=r(77),o=r(286);function a(){const e=r(0);return a=function(){return e},e}function l(){const e=r(27);return l=function(){return e},e}function c(){const e=r(10);return c=function(){return e},e}function u(){const e=r(21);return u=function(){return e},e}Object.defineProperty(t,"types",{enumerable:!0,get:function(){return a()}});var p=r(78),f=r(486),d=r(498),h=r(499),m=r(500);t.version="7.14.6";const y=Object.freeze([".js",".jsx",".es6",".es",".mjs",".cjs"]);t.DEFAULT_EXTENSIONS=y,t.OptionManager=class{init(e){return(0,p.loadOptions)(e)}}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"NodePath",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"Scope",{enumerable:!0,get:function(){return l.default}}),Object.defineProperty(t,"Hub",{enumerable:!0,get:function(){return c.default}}),t.visitors=t.default=void 0;var n=r(362),s=r(455);t.visitors=s;var i=r(0),o=r(34),a=r(19),l=r(231),c=r(456);function u(e,t={},r,n,o){if(e){if(!t.noScope&&!r&&"Program"!==e.type&&"File"!==e.type)throw new Error(`You must pass a scope and parentPath unless traversing a Program/File. Instead of that you tried to traverse a ${e.type} node without passing scope and parentPath.`);i.VISITOR_KEYS[e.type]&&(s.explode(t),u.node(e,t,r,n,o))}}var p=u;function f(e,t){e.node.type===t.type&&(t.has=!0,e.stop())}t.default=p,u.visitors=s,u.verify=s.verify,u.explode=s.explode,u.cheap=function(e,t){return i.traverseFast(e,t)},u.node=function(e,t,r,s,o,a){const l=i.VISITOR_KEYS[e.type];if(!l)return;const c=new n.default(r,t,s,o);for(const t of l)if((!a||!a[t])&&c.visit(e,t))return},u.clearNode=function(e,t){i.removeProperties(e,t),o.path.delete(e)},u.removeProperties=function(e,t){return i.traverseFast(e,u.clearNode,t),e},u.hasType=function(e,t,r){if(null!=r&&r.includes(e.type))return!1;if(e.type===t)return!0;const n={has:!1,type:t};return u(e,{noScope:!0,denylist:r,enter:f},null,n),n.has},u.cache=o},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"VISITOR_KEYS",{enumerable:!0,get:function(){return s.VISITOR_KEYS}}),Object.defineProperty(t,"ALIAS_KEYS",{enumerable:!0,get:function(){return s.ALIAS_KEYS}}),Object.defineProperty(t,"FLIPPED_ALIAS_KEYS",{enumerable:!0,get:function(){return s.FLIPPED_ALIAS_KEYS}}),Object.defineProperty(t,"NODE_FIELDS",{enumerable:!0,get:function(){return s.NODE_FIELDS}}),Object.defineProperty(t,"BUILDER_KEYS",{enumerable:!0,get:function(){return s.BUILDER_KEYS}}),Object.defineProperty(t,"DEPRECATED_KEYS",{enumerable:!0,get:function(){return s.DEPRECATED_KEYS}}),Object.defineProperty(t,"NODE_PARENT_VALIDATIONS",{enumerable:!0,get:function(){return s.NODE_PARENT_VALIDATIONS}}),Object.defineProperty(t,"PLACEHOLDERS",{enumerable:!0,get:function(){return i.PLACEHOLDERS}}),Object.defineProperty(t,"PLACEHOLDERS_ALIAS",{enumerable:!0,get:function(){return i.PLACEHOLDERS_ALIAS}}),Object.defineProperty(t,"PLACEHOLDERS_FLIPPED_ALIAS",{enumerable:!0,get:function(){return i.PLACEHOLDERS_FLIPPED_ALIAS}}),t.TYPES=void 0;var n=r(215);r(128),r(370),r(371),r(372),r(373),r(374);var s=r(20),i=r(217);n(s.VISITOR_KEYS),n(s.ALIAS_KEYS),n(s.FLIPPED_ALIAS_KEYS),n(s.NODE_FIELDS),n(s.BUILDER_KEYS),n(s.DEPRECATED_KEYS),n(i.PLACEHOLDERS_ALIAS),n(i.PLACEHOLDERS_FLIPPED_ALIAS);const o=Object.keys(s.VISITOR_KEYS).concat(Object.keys(s.FLIPPED_ALIAS_KEYS)).concat(Object.keys(s.DEPRECATED_KEYS));t.TYPES=o},(e,t,r)=>{const n=r(3);e.exports=(e,t,r)=>new n(e,r).compare(new n(t,r))},(e,t,r)=>{class n{constructor(e,t){if(t=i(t),e instanceof n)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new n(e.raw,t);if(e instanceof o)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map((e=>this.parseRange(e.trim()))).filter((e=>e.length)),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${e}`);if(this.set.length>1){const e=this.set[0];if(this.set=this.set.filter((e=>!h(e[0]))),0===this.set.length)this.set=[e];else if(this.set.length>1)for(const e of this.set)if(1===e.length&&m(e[0])){this.set=[e];break}}this.format()}format(){return this.range=this.set.map((e=>e.join(" ").trim())).join("||").trim(),this.range}toString(){return this.range}parseRange(e){e=e.trim();const t=`parseRange:${Object.keys(this.options).join(",")}:${e}`,r=s.get(t);if(r)return r;const n=this.options.loose,i=n?c[u.HYPHENRANGELOOSE]:c[u.HYPHENRANGE];e=e.replace(i,O(this.options.includePrerelease)),a("hyphen replace",e),e=e.replace(c[u.COMPARATORTRIM],p),a("comparator trim",e,c[u.COMPARATORTRIM]),e=(e=(e=e.replace(c[u.TILDETRIM],f)).replace(c[u.CARETTRIM],d)).split(/\s+/).join(" ");const l=n?c[u.COMPARATORLOOSE]:c[u.COMPARATOR],m=e.split(" ").map((e=>g(e,this.options))).join(" ").split(/\s+/).map((e=>A(e,this.options))).filter(this.options.loose?e=>!!e.match(l):()=>!0).map((e=>new o(e,this.options))),y=(m.length,new Map);for(const e of m){if(h(e))return[e];y.set(e.value,e)}y.size>1&&y.has("")&&y.delete("");const b=[...y.values()];return s.set(t,b),b}intersects(e,t){if(!(e instanceof n))throw new TypeError("a Range is required");return this.set.some((r=>y(r,t)&&e.set.some((e=>y(e,t)&&r.every((r=>e.every((e=>r.intersects(e,t)))))))))}test(e){if(!e)return!1;if("string"==typeof e)try{e=new l(e,this.options)}catch(e){return!1}for(let t=0;t"<0.0.0-0"===e.value,m=e=>""===e.value,y=(e,t)=>{let r=!0;const n=e.slice();let s=n.pop();for(;r&&n.length;)r=n.every((e=>s.intersects(e,t))),s=n.pop();return r},g=(e,t)=>(a("comp",e,t),e=x(e,t),a("caret",e),e=v(e,t),a("tildes",e),e=T(e,t),a("xrange",e),e=P(e,t),a("stars",e),e),b=e=>!e||"x"===e.toLowerCase()||"*"===e,v=(e,t)=>e.trim().split(/\s+/).map((e=>E(e,t))).join(" "),E=(e,t)=>{const r=t.loose?c[u.TILDELOOSE]:c[u.TILDE];return e.replace(r,((t,r,n,s,i)=>{let o;return a("tilde",e,t,r,n,s,i),b(r)?o="":b(n)?o=`>=${r}.0.0 <${+r+1}.0.0-0`:b(s)?o=`>=${r}.${n}.0 <${r}.${+n+1}.0-0`:i?(a("replaceTilde pr",i),o=`>=${r}.${n}.${s}-${i} <${r}.${+n+1}.0-0`):o=`>=${r}.${n}.${s} <${r}.${+n+1}.0-0`,a("tilde return",o),o}))},x=(e,t)=>e.trim().split(/\s+/).map((e=>S(e,t))).join(" "),S=(e,t)=>{a("caret",e,t);const r=t.loose?c[u.CARETLOOSE]:c[u.CARET],n=t.includePrerelease?"-0":"";return e.replace(r,((t,r,s,i,o)=>{let l;return a("caret",e,t,r,s,i,o),b(r)?l="":b(s)?l=`>=${r}.0.0${n} <${+r+1}.0.0-0`:b(i)?l="0"===r?`>=${r}.${s}.0${n} <${r}.${+s+1}.0-0`:`>=${r}.${s}.0${n} <${+r+1}.0.0-0`:o?(a("replaceCaret pr",o),l="0"===r?"0"===s?`>=${r}.${s}.${i}-${o} <${r}.${s}.${+i+1}-0`:`>=${r}.${s}.${i}-${o} <${r}.${+s+1}.0-0`:`>=${r}.${s}.${i}-${o} <${+r+1}.0.0-0`):(a("no pr"),l="0"===r?"0"===s?`>=${r}.${s}.${i}${n} <${r}.${s}.${+i+1}-0`:`>=${r}.${s}.${i}${n} <${r}.${+s+1}.0-0`:`>=${r}.${s}.${i} <${+r+1}.0.0-0`),a("caret return",l),l}))},T=(e,t)=>(a("replaceXRanges",e,t),e.split(/\s+/).map((e=>w(e,t))).join(" ")),w=(e,t)=>{e=e.trim();const r=t.loose?c[u.XRANGELOOSE]:c[u.XRANGE];return e.replace(r,((r,n,s,i,o,l)=>{a("xRange",e,r,n,s,i,o,l);const c=b(s),u=c||b(i),p=u||b(o),f=p;return"="===n&&f&&(n=""),l=t.includePrerelease?"-0":"",c?r=">"===n||"<"===n?"<0.0.0-0":"*":n&&f?(u&&(i=0),o=0,">"===n?(n=">=",u?(s=+s+1,i=0,o=0):(i=+i+1,o=0)):"<="===n&&(n="<",u?s=+s+1:i=+i+1),"<"===n&&(l="-0"),r=`${n+s}.${i}.${o}${l}`):u?r=`>=${s}.0.0${l} <${+s+1}.0.0-0`:p&&(r=`>=${s}.${i}.0${l} <${s}.${+i+1}.0-0`),a("xRange return",r),r}))},P=(e,t)=>(a("replaceStars",e,t),e.trim().replace(c[u.STAR],"")),A=(e,t)=>(a("replaceGTE0",e,t),e.trim().replace(c[t.includePrerelease?u.GTE0PRE:u.GTE0],"")),O=e=>(t,r,n,s,i,o,a,l,c,u,p,f,d)=>`${r=b(n)?"":b(s)?`>=${n}.0.0${e?"-0":""}`:b(i)?`>=${n}.${s}.0${e?"-0":""}`:o?`>=${r}`:`>=${r}${e?"-0":""}`} ${l=b(c)?"":b(u)?`<${+c+1}.0.0-0`:b(p)?`<${c}.${+u+1}.0-0`:f?`<=${c}.${u}.${p}-${f}`:e?`<${c}.${u}.${+p+1}-0`:`<=${l}`}`.trim(),C=(e,t,r)=>{for(let r=0;r0){const n=e[r].semver;if(n.major===t.major&&n.minor===t.minor&&n.patch===t.patch)return!0}return!1}return!0}},e=>{"use strict";const t=Symbol.for("gensync:v1:start"),r=Symbol.for("gensync:v1:suspend"),n="GENSYNC_OPTIONS_ERROR",s="GENSYNC_RACE_NONEMPTY";function i(e,t,r,s){if(typeof r===e||s&&void 0===r)return;let i;throw i=s?`Expected opts.${t} to be either a ${e}, or undefined.`:`Expected opts.${t} to be a ${e}.`,o(i,n)}function o(e,t){return Object.assign(new Error(e),{code:t})}function a({name:e,arity:n,sync:s,async:i}){return d(e,n,(function*(...e){const n=yield t;if(!n)return s.call(this,e);let o;try{i.call(this,e,(e=>{o||(o={value:e},n())}),(e=>{o||(o={err:e},n())}))}catch(e){o={err:e},n()}if(yield r,o.hasOwnProperty("err"))throw o.err;return o.value}))}function l(e){let t;for(;!({value:t}=e.next()).done;)u(t,e);return t}function c(e,t,r){!function n(){try{let r;for(;!({value:r}=e.next()).done;){u(r,e);let t=!0,s=!1;const i=e.next((()=>{t?s=!0:n()}));if(t=!1,p(i,e),!s)return}return t(r)}catch(e){return r(e)}}()}function u(e,r){e!==t&&f(r,o(`Got unexpected yielded value in gensync generator: ${JSON.stringify(e)}. Did you perhaps mean to use 'yield*' instead of 'yield'?`,"GENSYNC_EXPECTED_START"))}function p({value:e,done:t},n){(t||e!==r)&&f(n,o(t?"Unexpected generator completion. If you get this, it is probably a gensync bug.":`Expected GENSYNC_SUSPEND, got ${JSON.stringify(e)}. If you get this, it is probably a gensync bug.`,"GENSYNC_EXPECTED_SUSPEND"))}function f(e,t){throw e.throw&&e.throw(t),t}function d(e,t,r){if("string"==typeof e){const t=Object.getOwnPropertyDescriptor(r,"name");t&&!t.configurable||Object.defineProperty(r,"name",Object.assign(t||{},{configurable:!0,value:e}))}if("number"==typeof t){const e=Object.getOwnPropertyDescriptor(r,"length");e&&!e.configurable||Object.defineProperty(r,"length",Object.assign(e||{},{configurable:!0,value:t}))}return r}e.exports=Object.assign((function(e){let t=e;return t="function"!=typeof e?function({name:e,arity:t,sync:r,async:s,errback:l}){if(i("string","name",e,!0),i("number","arity",t,!0),i("function","sync",r),i("function","async",s,!0),i("function","errback",l,!0),s&&l)throw o("Expected one of either opts.async or opts.errback, but got _both_.",n);if("string"!=typeof e){let t;l&&l.name&&"errback"!==l.name&&(t=l.name),s&&s.name&&"async"!==s.name&&(t=s.name.replace(/Async$/,"")),r&&r.name&&"sync"!==r.name&&(t=r.name.replace(/Sync$/,"")),"string"==typeof t&&(e=t)}return"number"!=typeof t&&(t=r.length),a({name:e,arity:t,sync:function(e){return r.apply(this,e)},async:function(e,t,n){s?s.apply(this,e).then(t,n):l?l.call(this,...e,((e,r)=>{null==e?t(r):n(e)})):t(r.apply(this,e))}})}(e):function(e){return d(e.name,e.length,(function(...t){return e.apply(this,t)}))}(e),Object.assign(t,function(e){return{sync:function(...t){return l(e.apply(this,t))},async:function(...t){return new Promise(((r,n)=>{c(e.apply(this,t),r,n)}))},errback:function(...t){const r=t.pop();if("function"!=typeof r)throw o("Asynchronous function called without callback","GENSYNC_ERRBACK_NO_CALLBACK");let n;try{n=e.apply(this,t)}catch(e){return void r(e)}c(n,(e=>r(void 0,e)),(e=>r(e)))}}}(t))}),{all:a({name:"all",arity:1,sync:function(e){return Array.from(e[0]).map((e=>l(e)))},async:function(e,t,r){const n=Array.from(e[0]);if(0===n.length)return void Promise.resolve().then((()=>t([])));let s=0;const i=n.map((()=>{}));n.forEach(((e,n)=>{c(e,(e=>{i[n]=e,s+=1,s===i.length&&t(i)}),r)}))}}),race:a({name:"race",arity:1,sync:function(e){const t=Array.from(e[0]);if(0===t.length)throw o("Must race at least 1 item",s);return l(t[0])},async:function(e,t,r){const n=Array.from(e[0]);if(0===n.length)throw o("Must race at least 1 item",s);for(const e of n)c(e,t,r)}})})},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n=r(91);function s(e,t){for(var r=0;re||this.source.end.linet||this.source.end.line===e&&this.source.end.column{e.exports=function(e){try{return!!e()}catch(e){return!0}}},(e,t,r)=>{var n=r(109),s={}.hasOwnProperty;e.exports=Object.hasOwn||function(e,t){return s.call(n(e),t)}},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const a=i(r(0)),l=o(r(21)),c=o(r(531)),u=r(146),p=o(r(167)),f=o(r(170)),d=/\*?\s*@jsx\s+([^\s]+)/;t.default=({types:e})=>({name:"babel-plugin-jsx",inherits:c.default,visitor:Object.assign(Object.assign(Object.assign({},p.default),f.default),{Program:{enter(t,r){if((e=>{let t=!1;return e.traverse({JSXElement(e){t=!0,e.stop()},JSXFragment(e){t=!0,e.stop()}}),t})(t)){const n=["createVNode","Fragment","resolveComponent","withDirectives","vShow","vModelSelect","vModelText","vModelCheckbox","vModelRadio","vModelText","vModelDynamic","resolveDirective","mergeProps","createTextVNode","isVNode"];if(u.isModule(t)){const s={};n.forEach((n=>{r.set(n,(()=>{if(s[n])return e.cloneNode(s[n]);const r=u.addNamed(t,n,"vue",{ensureLiveReference:!0});return s[n]=r,r}))}));const{enableObjectSlots:i=!0}=r.opts;i&&r.set("@vue/babel-plugin-jsx/runtimeIsSlot",(()=>{if(s.runtimeIsSlot)return s.runtimeIsSlot;const{name:e}=r.get("isVNode")(),n=t.scope.generateUidIdentifier("isSlot"),i=l.default.ast` function ${n.name}(s) { return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${e}(s)); } `,o=t.get("body").filter((e=>e.isImportDeclaration())).pop();return o&&o.insertAfter(i),s.runtimeIsSlot=n,n}))}else{let e="";n.forEach((n=>{r.set(n,(()=>(e||(e=u.addNamespace(t,"vue",{ensureLiveReference:!0}).name),a.memberExpression(a.identifier(e),a.identifier(n)))))}))}const{opts:{pragma:s=""},file:i}=r;if(s&&r.set("createVNode",(()=>a.identifier(s))),i.ast.comments)for(const e of i.ast.comments){const t=d.exec(e.value);t&&r.set("createVNode",(()=>a.identifier(t[1])))}}},exit(e){const t=e.get("body"),r=new Map;t.filter((e=>a.isImportDeclaration(e.node)&&"vue"===e.node.source.value)).forEach((e=>{const{specifiers:t}=e.node;let n=!1;t.forEach((e=>{!e.loc&&a.isImportSpecifier(e)&&a.isIdentifier(e.imported)&&(r.set(e.imported.name,e),n=!0)})),n&&e.remove()}));const n=[...r.keys()].map((e=>r.get(e)));n.length&&e.unshiftContainer("body",a.importDeclaration(n,a.stringLiteral("vue")))}}})})},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.SHOULD_SKIP=t.SHOULD_STOP=t.REMOVED=void 0;var n=r(212),s=r(65),i=r(10),o=r(231),a=r(0),l=r(34),c=r(133),u=r(433),p=r(434),f=r(437),d=r(440),h=r(441),m=r(447),y=r(448),g=r(449),b=r(451),v=r(453),E=r(454);const x=s("babel");t.REMOVED=1,t.SHOULD_STOP=2,t.SHOULD_SKIP=4;class S{constructor(e,t){this.contexts=[],this.state=null,this.opts=null,this._traverseFlags=0,this.skipKeys=null,this.parentPath=null,this.container=null,this.listKey=null,this.key=null,this.node=null,this.type=null,this.parent=t,this.hub=e,this.data=null,this.context=null,this.scope=null}static get({hub:e,parentPath:t,parent:r,container:n,listKey:s,key:i}){if(!e&&t&&(e=t.hub),!r)throw new Error("To get a node path the parent needs to exist");const o=n[i];let a=l.path.get(r);a||(a=new Map,l.path.set(r,a));let c=a.get(o);return c||(c=new S(e,r),o&&a.set(o,c)),c.setup(t,n,s,i),c}getScope(e){return this.isScope()?new o.default(this):e}setData(e,t){return null==this.data&&(this.data=Object.create(null)),this.data[e]=t}getData(e,t){null==this.data&&(this.data=Object.create(null));let r=this.data[e];return void 0===r&&void 0!==t&&(r=this.data[e]=t),r}buildCodeFrameError(e,t=SyntaxError){return this.hub.buildError(this.node,e,t)}traverse(e,t){(0,i.default)(this.node,e,this.scope,t,this)}set(e,t){a.validate(this.node,e,t),this.node[e]=t}getPathLocation(){const e=[];let t=this;do{let r=t.key;t.inList&&(r=`${t.listKey}[${r}]`),e.unshift(r)}while(t=t.parentPath);return e.join(".")}debug(e){x.enabled&&x(`${this.getPathLocation()} ${this.type}: ${e}`)}toString(){return(0,c.default)(this.node).code}get inList(){return!!this.listKey}set inList(e){e||(this.listKey=null)}get parentKey(){return this.listKey||this.key}get shouldSkip(){return!!(4&this._traverseFlags)}set shouldSkip(e){e?this._traverseFlags|=4:this._traverseFlags&=-5}get shouldStop(){return!!(2&this._traverseFlags)}set shouldStop(e){e?this._traverseFlags|=2:this._traverseFlags&=-3}get removed(){return!!(1&this._traverseFlags)}set removed(e){e?this._traverseFlags|=1:this._traverseFlags&=-2}}Object.assign(S.prototype,u,p,f,d,h,m,y,g,b,v,E);for(const e of a.TYPES){const t=`is${e}`,r=a[t];S.prototype[t]=function(e){return r(this.node,e)},S.prototype[`assert${e}`]=function(t){if(!r(this.node,t))throw new TypeError(`Expected node path of type ${e}`)}}for(const e of Object.keys(n)){if("_"===e[0])continue;a.TYPES.indexOf(e)<0&&a.TYPES.push(e);const t=n[e];S.prototype[`is${e}`]=function(e){return t.checkPath(this,e)}}var T=S;t.default=T},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.validate=d,t.typeIs=h,t.validateType=function(e){return d(h(e))},t.validateOptional=function(e){return{validate:e,optional:!0}},t.validateOptionalType=function(e){return{validate:h(e),optional:!0}},t.arrayOf=m,t.arrayOfType=y,t.validateArrayOfType=function(e){return d(y(e))},t.assertEach=g,t.assertOneOf=function(...e){function t(t,r,n){if(e.indexOf(n)<0)throw new TypeError(`Property ${r} expected value to be one of ${JSON.stringify(e)} but got ${JSON.stringify(n)}`)}return t.oneOf=e,t},t.assertNodeType=b,t.assertNodeOrValueType=function(...e){function t(t,r,i){for(const o of e)if(f(i)===o||(0,n.default)(o,i))return void(0,s.validateChild)(t,r,i);throw new TypeError(`Property ${r} of ${t.type} expected node to be of a type ${JSON.stringify(e)} but instead got ${JSON.stringify(null==i?void 0:i.type)}`)}return t.oneOfNodeOrValueTypes=e,t},t.assertValueType=v,t.assertShape=function(e){function t(t,r,n){const i=[];for(const r of Object.keys(e))try{(0,s.validateField)(t,r,n[r],e[r])}catch(e){if(e instanceof TypeError){i.push(e.message);continue}throw e}if(i.length)throw new TypeError(`Property ${r} of ${t.type} expected to have the following:\n${i.join("\n")}`)}return t.shapeOf=e,t},t.assertOptionalChainStart=function(){return function(e){var t;let r=e;for(;e;){const{type:e}=r;if("OptionalCallExpression"!==e){if("OptionalMemberExpression"!==e)break;if(r.optional)return;r=r.object}else{if(r.optional)return;r=r.callee}}throw new TypeError(`Non-optional ${e.type} must chain from an optional OptionalMemberExpression or OptionalCallExpression. Found chain from ${null==(t=r)?void 0:t.type}`)}},t.chain=E,t.default=function(e,t={}){const r=t.inherits&&T[t.inherits]||{};let n=t.fields;if(!n&&(n={},r.fields)){const e=Object.getOwnPropertyNames(r.fields);for(const t of e){const e=r.fields[t],s=e.default;if(Array.isArray(s)?s.length>0:s&&"object"==typeof s)throw new Error("field defaults can only be primitives or empty arrays currently");n[t]={default:Array.isArray(s)?[]:s,optional:e.optional,validate:e.validate}}}const s=t.visitor||r.visitor||[],d=t.aliases||r.aliases||[],h=t.builder||r.builder||t.visitor||[];for(const r of Object.keys(t))if(-1===x.indexOf(r))throw new Error(`Unknown type option "${r}" on ${e}`);t.deprecatedAlias&&(u[t.deprecatedAlias]=e);for(const e of s.concat(h))n[e]=n[e]||{};for(const t of Object.keys(n)){const r=n[t];void 0!==r.default&&-1===h.indexOf(t)&&(r.optional=!0),void 0===r.default?r.default=null:r.validate||null==r.default||(r.validate=v(f(r.default)));for(const n of Object.keys(r))if(-1===S.indexOf(n))throw new Error(`Unknown field key "${n}" on ${e}.${t}`)}i[e]=t.visitor=s,c[e]=t.builder=h,l[e]=t.fields=n,o[e]=t.aliases=d,d.forEach((t=>{a[t]=a[t]||[],a[t].push(e)})),t.validate&&(p[e]=t.validate),T[e]=t},t.NODE_PARENT_VALIDATIONS=t.DEPRECATED_KEYS=t.BUILDER_KEYS=t.NODE_FIELDS=t.FLIPPED_ALIAS_KEYS=t.ALIAS_KEYS=t.VISITOR_KEYS=void 0;var n=r(62),s=r(130);const i={};t.VISITOR_KEYS=i;const o={};t.ALIAS_KEYS=o;const a={};t.FLIPPED_ALIAS_KEYS=a;const l={};t.NODE_FIELDS=l;const c={};t.BUILDER_KEYS=c;const u={};t.DEPRECATED_KEYS=u;const p={};function f(e){return Array.isArray(e)?"array":null===e?"null":typeof e}function d(e){return{validate:e}}function h(e){return"string"==typeof e?b(e):b(...e)}function m(e){return E(v("array"),g(e))}function y(e){return m(h(e))}function g(e){function t(t,r,n){if(Array.isArray(n))for(let s=0;s=2&&"type"in e[0]&&"array"===e[0].type&&!("each"in e[1]))throw new Error('An assertValueType("array") validator can only be followed by an assertEach(...) validator.');return t}t.NODE_PARENT_VALIDATIONS=p;const x=["aliases","builder","deprecatedAlias","fields","inherits","visitor","validate"],S=["default","optional","validate"],T={}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.program=t.expression=t.statements=t.statement=t.smart=void 0;var n=r(443),s=r(444);const i=(0,s.default)(n.smart);t.smart=i;const o=(0,s.default)(n.statement);t.statement=o;const a=(0,s.default)(n.statements);t.statements=a;const l=(0,s.default)(n.expression);t.expression=l;const c=(0,s.default)(n.program);t.program=c;var u=Object.assign(i.bind(void 0),{smart:i,statement:o,statements:a,expression:l,program:c,ast:i.ast});t.default=u},(e,t,r)=>{"use strict";let n,s,i,{isClean:o,my:a}=r(154),l=r(47),c=r(49),u=r(48);function p(e){return e.map((e=>(e.nodes&&(e.nodes=p(e.nodes)),delete e.source,e)))}function f(e){if(e[o]=!1,e.proxyOf.nodes)for(let t of e.proxyOf.nodes)f(t)}class d extends u{push(e){return e.parent=this,this.proxyOf.nodes.push(e),this}each(e){if(!this.proxyOf.nodes)return;let t,r,n=this.getIterator();for(;this.indexes[n]{let n;try{n=e(t,r)}catch(e){throw t.addToError(e)}return!1!==n&&t.walk&&(n=t.walk(e)),n}))}walkDecls(e,t){return t?e instanceof RegExp?this.walk(((r,n)=>{if("decl"===r.type&&e.test(r.prop))return t(r,n)})):this.walk(((r,n)=>{if("decl"===r.type&&r.prop===e)return t(r,n)})):(t=e,this.walk(((e,r)=>{if("decl"===e.type)return t(e,r)})))}walkRules(e,t){return t?e instanceof RegExp?this.walk(((r,n)=>{if("rule"===r.type&&e.test(r.selector))return t(r,n)})):this.walk(((r,n)=>{if("rule"===r.type&&r.selector===e)return t(r,n)})):(t=e,this.walk(((e,r)=>{if("rule"===e.type)return t(e,r)})))}walkAtRules(e,t){return t?e instanceof RegExp?this.walk(((r,n)=>{if("atrule"===r.type&&e.test(r.name))return t(r,n)})):this.walk(((r,n)=>{if("atrule"===r.type&&r.name===e)return t(r,n)})):(t=e,this.walk(((e,r)=>{if("atrule"===e.type)return t(e,r)})))}walkComments(e){return this.walk(((t,r)=>{if("comment"===t.type)return e(t,r)}))}append(...e){for(let t of e){let e=this.normalize(t,this.last);for(let t of e)this.proxyOf.nodes.push(t)}return this.markDirty(),this}prepend(...e){e=e.reverse();for(let t of e){let e=this.normalize(t,this.first,"prepend").reverse();for(let t of e)this.proxyOf.nodes.unshift(t);for(let t in this.indexes)this.indexes[t]=this.indexes[t]+e.length}return this.markDirty(),this}cleanRaws(e){if(super.cleanRaws(e),this.nodes)for(let t of this.nodes)t.cleanRaws(e)}insertBefore(e,t){let r,n=0===(e=this.index(e))&&"prepend",s=this.normalize(t,this.proxyOf.nodes[e],n).reverse();for(let t of s)this.proxyOf.nodes.splice(e,0,t);for(let t in this.indexes)r=this.indexes[t],e<=r&&(this.indexes[t]=r+s.length);return this.markDirty(),this}insertAfter(e,t){e=this.index(e);let r,n=this.normalize(t,this.proxyOf.nodes[e]).reverse();for(let t of n)this.proxyOf.nodes.splice(e+1,0,t);for(let t in this.indexes)r=this.indexes[t],e=e&&(this.indexes[r]=t-1);return this.markDirty(),this}removeAll(){for(let e of this.proxyOf.nodes)e.parent=void 0;return this.proxyOf.nodes=[],this.markDirty(),this}replaceValues(e,t,r){return r||(r=t,t={}),this.walkDecls((n=>{t.props&&!t.props.includes(n.prop)||t.fast&&!n.value.includes(t.fast)||(n.value=n.value.replace(e,r))})),this.markDirty(),this}every(e){return this.nodes.every(e)}some(e){return this.nodes.some(e)}index(e){return"number"==typeof e?e:(e.proxyOf&&(e=e.proxyOf),this.proxyOf.nodes.indexOf(e))}get first(){if(this.proxyOf.nodes)return this.proxyOf.nodes[0]}get last(){if(this.proxyOf.nodes)return this.proxyOf.nodes[this.proxyOf.nodes.length-1]}normalize(e,t){if("string"==typeof e)e=p(n(e).nodes);else if(Array.isArray(e)){e=e.slice(0);for(let t of e)t.parent&&t.parent.removeChild(t,"ignore")}else if("root"===e.type&&"document"!==this.type){e=e.nodes.slice(0);for(let t of e)t.parent&&t.parent.removeChild(t,"ignore")}else if(e.type)e=[e];else if(e.prop){if(void 0===e.value)throw new Error("Value field is missed in node creation");"string"!=typeof e.value&&(e.value=String(e.value)),e=[new l(e)]}else if(e.selector)e=[new s(e)];else if(e.name)e=[new i(e)];else{if(!e.text)throw new Error("Unknown node type in node creation");e=[new c(e)]}return e.map((e=>(e[a]||d.rebuild(e),(e=e.proxyOf).parent&&e.parent.removeChild(e),e[o]&&f(e),void 0===e.raws.before&&t&&void 0!==t.raws.before&&(e.raws.before=t.raws.before.replace(/\S/g,"")),e.parent=this,e)))}getProxyProcessor(){return{set:(e,t,r)=>(e[t]===r||(e[t]=r,"name"!==t&&"params"!==t&&"selector"!==t||e.markDirty()),!0),get:(e,t)=>"proxyOf"===t?e:e[t]?"each"===t||"string"==typeof t&&t.startsWith("walk")?(...r)=>e[t](...r.map((e=>"function"==typeof e?(t,r)=>e(t.toProxy(),r):e))):"every"===t||"some"===t?r=>e[t](((e,...t)=>r(e.toProxy(),...t))):"root"===t?()=>e.root().toProxy():"nodes"===t?e.nodes.map((e=>e.toProxy())):"first"===t||"last"===t?e[t].toProxy():e[t]:e[t]}}getIterator(){this.lastEach||(this.lastEach=0),this.indexes||(this.indexes={}),this.lastEach+=1;let e=this.lastEach;return this.indexes[e]=0,e}}d.registerParse=e=>{n=e},d.registerRule=e=>{s=e},d.registerAtRule=e=>{i=e},e.exports=d,d.default=d,d.rebuild=e=>{"atrule"===e.type?Object.setPrototypeOf(e,i.prototype):"rule"===e.type?Object.setPrototypeOf(e,s.prototype):"decl"===e.type?Object.setPrototypeOf(e,l.prototype):"comment"===e.type&&Object.setPrototypeOf(e,c.prototype),e[a]=!0,e.nodes&&e.nodes.forEach((e=>{d.rebuild(e)}))}},(e,t,r)=>{const{MAX_SAFE_COMPONENT_LENGTH:n}=r(41),s=r(42),i=(t=e.exports={}).re=[],o=t.src=[],a=t.t={};let l=0;const c=(e,t,r)=>{const n=l++;s(n,t),a[e]=n,o[n]=t,i[n]=new RegExp(t,r?"g":void 0)};c("NUMERICIDENTIFIER","0|[1-9]\\d*"),c("NUMERICIDENTIFIERLOOSE","[0-9]+"),c("NONNUMERICIDENTIFIER","\\d*[a-zA-Z-][a-zA-Z0-9-]*"),c("MAINVERSION",`(${o[a.NUMERICIDENTIFIER]})\\.(${o[a.NUMERICIDENTIFIER]})\\.(${o[a.NUMERICIDENTIFIER]})`),c("MAINVERSIONLOOSE",`(${o[a.NUMERICIDENTIFIERLOOSE]})\\.(${o[a.NUMERICIDENTIFIERLOOSE]})\\.(${o[a.NUMERICIDENTIFIERLOOSE]})`),c("PRERELEASEIDENTIFIER",`(?:${o[a.NUMERICIDENTIFIER]}|${o[a.NONNUMERICIDENTIFIER]})`),c("PRERELEASEIDENTIFIERLOOSE",`(?:${o[a.NUMERICIDENTIFIERLOOSE]}|${o[a.NONNUMERICIDENTIFIER]})`),c("PRERELEASE",`(?:-(${o[a.PRERELEASEIDENTIFIER]}(?:\\.${o[a.PRERELEASEIDENTIFIER]})*))`),c("PRERELEASELOOSE",`(?:-?(${o[a.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${o[a.PRERELEASEIDENTIFIERLOOSE]})*))`),c("BUILDIDENTIFIER","[0-9A-Za-z-]+"),c("BUILD",`(?:\\+(${o[a.BUILDIDENTIFIER]}(?:\\.${o[a.BUILDIDENTIFIER]})*))`),c("FULLPLAIN",`v?${o[a.MAINVERSION]}${o[a.PRERELEASE]}?${o[a.BUILD]}?`),c("FULL",`^${o[a.FULLPLAIN]}$`),c("LOOSEPLAIN",`[v=\\s]*${o[a.MAINVERSIONLOOSE]}${o[a.PRERELEASELOOSE]}?${o[a.BUILD]}?`),c("LOOSE",`^${o[a.LOOSEPLAIN]}$`),c("GTLT","((?:<|>)?=?)"),c("XRANGEIDENTIFIERLOOSE",`${o[a.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`),c("XRANGEIDENTIFIER",`${o[a.NUMERICIDENTIFIER]}|x|X|\\*`),c("XRANGEPLAIN",`[v=\\s]*(${o[a.XRANGEIDENTIFIER]})(?:\\.(${o[a.XRANGEIDENTIFIER]})(?:\\.(${o[a.XRANGEIDENTIFIER]})(?:${o[a.PRERELEASE]})?${o[a.BUILD]}?)?)?`),c("XRANGEPLAINLOOSE",`[v=\\s]*(${o[a.XRANGEIDENTIFIERLOOSE]})(?:\\.(${o[a.XRANGEIDENTIFIERLOOSE]})(?:\\.(${o[a.XRANGEIDENTIFIERLOOSE]})(?:${o[a.PRERELEASELOOSE]})?${o[a.BUILD]}?)?)?`),c("XRANGE",`^${o[a.GTLT]}\\s*${o[a.XRANGEPLAIN]}$`),c("XRANGELOOSE",`^${o[a.GTLT]}\\s*${o[a.XRANGEPLAINLOOSE]}$`),c("COERCE",`(^|[^\\d])(\\d{1,${n}})(?:\\.(\\d{1,${n}}))?(?:\\.(\\d{1,${n}}))?(?:$|[^\\d])`),c("COERCERTL",o[a.COERCE],!0),c("LONETILDE","(?:~>?)"),c("TILDETRIM",`(\\s*)${o[a.LONETILDE]}\\s+`,!0),t.tildeTrimReplace="$1~",c("TILDE",`^${o[a.LONETILDE]}${o[a.XRANGEPLAIN]}$`),c("TILDELOOSE",`^${o[a.LONETILDE]}${o[a.XRANGEPLAINLOOSE]}$`),c("LONECARET","(?:\\^)"),c("CARETTRIM",`(\\s*)${o[a.LONECARET]}\\s+`,!0),t.caretTrimReplace="$1^",c("CARET",`^${o[a.LONECARET]}${o[a.XRANGEPLAIN]}$`),c("CARETLOOSE",`^${o[a.LONECARET]}${o[a.XRANGEPLAINLOOSE]}$`),c("COMPARATORLOOSE",`^${o[a.GTLT]}\\s*(${o[a.LOOSEPLAIN]})$|^$`),c("COMPARATOR",`^${o[a.GTLT]}\\s*(${o[a.FULLPLAIN]})$|^$`),c("COMPARATORTRIM",`(\\s*)${o[a.GTLT]}\\s*(${o[a.LOOSEPLAIN]}|${o[a.XRANGEPLAIN]})`,!0),t.comparatorTrimReplace="$1$2$3",c("HYPHENRANGE",`^\\s*(${o[a.XRANGEPLAIN]})\\s+-\\s+(${o[a.XRANGEPLAIN]})\\s*$`),c("HYPHENRANGELOOSE",`^\\s*(${o[a.XRANGEPLAINLOOSE]})\\s+-\\s+(${o[a.XRANGEPLAINLOOSE]})\\s*$`),c("STAR","(<|>)?=?\\s*\\*"),c("GTE0","^\\s*>=\\s*0.0.0\\s*$"),c("GTE0PRE","^\\s*>=\\s*0.0.0-0\\s*$")},e=>{e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NOT_LOCAL_BINDING=t.BLOCK_SCOPED_SYMBOL=t.INHERIT_KEYS=t.UNARY_OPERATORS=t.STRING_UNARY_OPERATORS=t.NUMBER_UNARY_OPERATORS=t.BOOLEAN_UNARY_OPERATORS=t.ASSIGNMENT_OPERATORS=t.BINARY_OPERATORS=t.NUMBER_BINARY_OPERATORS=t.BOOLEAN_BINARY_OPERATORS=t.COMPARISON_BINARY_OPERATORS=t.EQUALITY_BINARY_OPERATORS=t.BOOLEAN_NUMBER_BINARY_OPERATORS=t.UPDATE_OPERATORS=t.LOGICAL_OPERATORS=t.COMMENT_KEYS=t.FOR_INIT_KEYS=t.FLATTENABLE_KEYS=t.STATEMENT_OR_BLOCK_KEYS=void 0,t.STATEMENT_OR_BLOCK_KEYS=["consequent","body","alternate"],t.FLATTENABLE_KEYS=["body","expressions"],t.FOR_INIT_KEYS=["left","init"],t.COMMENT_KEYS=["leadingComments","trailingComments","innerComments"];const r=["||","&&","??"];t.LOGICAL_OPERATORS=r,t.UPDATE_OPERATORS=["++","--"];const n=[">","<",">=","<="];t.BOOLEAN_NUMBER_BINARY_OPERATORS=n;const s=["==","===","!=","!=="];t.EQUALITY_BINARY_OPERATORS=s;const i=[...s,"in","instanceof"];t.COMPARISON_BINARY_OPERATORS=i;const o=[...i,...n];t.BOOLEAN_BINARY_OPERATORS=o;const a=["-","/","%","*","**","&","|",">>",">>>","<<","^"];t.NUMBER_BINARY_OPERATORS=a;const l=["+",...a,...o];t.BINARY_OPERATORS=l;const c=["=","+=",...a.map((e=>e+"=")),...r.map((e=>e+"="))];t.ASSIGNMENT_OPERATORS=c;const u=["delete","!"];t.BOOLEAN_UNARY_OPERATORS=u;const p=["+","-","~"];t.NUMBER_UNARY_OPERATORS=p;const f=["typeof"];t.STRING_UNARY_OPERATORS=f;const d=["void","throw",...u,...p,...f];t.UNARY_OPERATORS=d,t.INHERIT_KEYS={optional:["typeAnnotation","typeParameters","returnType"],force:["start","loc","end"]};const h=Symbol.for("var used to be block scoped");t.BLOCK_SCOPED_SYMBOL=h;const m=Symbol.for("should not be considered a local binding");t.NOT_LOCAL_BINDING=m},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=l;var n=r(11),s=r(1);const i=Function.call.bind(Object.prototype.hasOwnProperty);function o(e,t,r){return e&&"string"==typeof e.type?l(e,t,r):e}function a(e,t,r){return Array.isArray(e)?e.map((e=>o(e,t,r))):o(e,t,r)}function l(e,t=!0,r=!1){if(!e)return e;const{type:o}=e,l={type:e.type};if((0,s.isIdentifier)(e))l.name=e.name,i(e,"optional")&&"boolean"==typeof e.optional&&(l.optional=e.optional),i(e,"typeAnnotation")&&(l.typeAnnotation=t?a(e.typeAnnotation,!0,r):e.typeAnnotation);else{if(!i(n.NODE_FIELDS,o))throw new Error(`Unknown node type: "${o}"`);for(const u of Object.keys(n.NODE_FIELDS[o]))i(e,u)&&(l[u]=t?(0,s.isFile)(e)&&"comments"===u?c(e.comments,t,r):a(e[u],!0,r):e[u])}return i(e,"loc")&&(l.loc=r?null:e.loc),i(e,"leadingComments")&&(l.leadingComments=c(e.leadingComments,t,r)),i(e,"innerComments")&&(l.innerComments=c(e.innerComments,t,r)),i(e,"trailingComments")&&(l.trailingComments=c(e.trailingComments,t,r)),i(e,"extra")&&(l.extra=Object.assign({},e.extra)),l}function c(e,t,r){return e&&t?e.map((({type:e,value:t,loc:n})=>r?{type:e,value:t,loc:null}:{type:e,value:t,loc:n})):e}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const r=!0,n=!0,s=!0,i=!0,o=!0;class a{constructor(e,t={}){this.label=void 0,this.keyword=void 0,this.beforeExpr=void 0,this.startsExpr=void 0,this.rightAssociative=void 0,this.isLoop=void 0,this.isAssign=void 0,this.prefix=void 0,this.postfix=void 0,this.binop=void 0,this.updateContext=void 0,this.label=e,this.keyword=t.keyword,this.beforeExpr=!!t.beforeExpr,this.startsExpr=!!t.startsExpr,this.rightAssociative=!!t.rightAssociative,this.isLoop=!!t.isLoop,this.isAssign=!!t.isAssign,this.prefix=!!t.prefix,this.postfix=!!t.postfix,this.binop=null!=t.binop?t.binop:null,this.updateContext=null}}const l=new Map;function c(e,t={}){t.keyword=e;const r=new a(e,t);return l.set(e,r),r}function u(e,t){return new a(e,{beforeExpr:r,binop:t})}const p={num:new a("num",{startsExpr:n}),bigint:new a("bigint",{startsExpr:n}),decimal:new a("decimal",{startsExpr:n}),regexp:new a("regexp",{startsExpr:n}),string:new a("string",{startsExpr:n}),name:new a("name",{startsExpr:n}),privateName:new a("#name",{startsExpr:n}),eof:new a("eof"),bracketL:new a("[",{beforeExpr:r,startsExpr:n}),bracketHashL:new a("#[",{beforeExpr:r,startsExpr:n}),bracketBarL:new a("[|",{beforeExpr:r,startsExpr:n}),bracketR:new a("]"),bracketBarR:new a("|]"),braceL:new a("{",{beforeExpr:r,startsExpr:n}),braceBarL:new a("{|",{beforeExpr:r,startsExpr:n}),braceHashL:new a("#{",{beforeExpr:r,startsExpr:n}),braceR:new a("}",{beforeExpr:r}),braceBarR:new a("|}"),parenL:new a("(",{beforeExpr:r,startsExpr:n}),parenR:new a(")"),comma:new a(",",{beforeExpr:r}),semi:new a(";",{beforeExpr:r}),colon:new a(":",{beforeExpr:r}),doubleColon:new a("::",{beforeExpr:r}),dot:new a("."),question:new a("?",{beforeExpr:r}),questionDot:new a("?."),arrow:new a("=>",{beforeExpr:r}),template:new a("template"),ellipsis:new a("...",{beforeExpr:r}),backQuote:new a("`",{startsExpr:n}),dollarBraceL:new a("${",{beforeExpr:r,startsExpr:n}),at:new a("@"),hash:new a("#",{startsExpr:n}),interpreterDirective:new a("#!..."),eq:new a("=",{beforeExpr:r,isAssign:i}),assign:new a("_=",{beforeExpr:r,isAssign:i}),slashAssign:new a("_=",{beforeExpr:r,isAssign:i}),incDec:new a("++/--",{prefix:o,postfix:!0,startsExpr:n}),bang:new a("!",{beforeExpr:r,prefix:o,startsExpr:n}),tilde:new a("~",{beforeExpr:r,prefix:o,startsExpr:n}),pipeline:u("|>",0),nullishCoalescing:u("??",1),logicalOR:u("||",1),logicalAND:u("&&",2),bitwiseOR:u("|",3),bitwiseXOR:u("^",4),bitwiseAND:u("&",5),equality:u("==/!=/===/!==",6),relational:u("/<=/>=",7),bitShift:u("<>/>>>",8),plusMin:new a("+/-",{beforeExpr:r,binop:9,prefix:o,startsExpr:n}),modulo:new a("%",{beforeExpr:r,binop:10,startsExpr:n}),star:new a("*",{binop:10}),slash:u("/",10),exponent:new a("**",{beforeExpr:r,binop:11,rightAssociative:!0}),_break:c("break"),_case:c("case",{beforeExpr:r}),_catch:c("catch"),_continue:c("continue"),_debugger:c("debugger"),_default:c("default",{beforeExpr:r}),_do:c("do",{isLoop:s,beforeExpr:r}),_else:c("else",{beforeExpr:r}),_finally:c("finally"),_for:c("for",{isLoop:s}),_function:c("function",{startsExpr:n}),_if:c("if"),_return:c("return",{beforeExpr:r}),_switch:c("switch"),_throw:c("throw",{beforeExpr:r,prefix:o,startsExpr:n}),_try:c("try"),_var:c("var"),_const:c("const"),_while:c("while",{isLoop:s}),_with:c("with"),_new:c("new",{beforeExpr:r,startsExpr:n}),_this:c("this",{startsExpr:n}),_super:c("super",{startsExpr:n}),_class:c("class",{startsExpr:n}),_extends:c("extends",{beforeExpr:r}),_export:c("export"),_import:c("import",{startsExpr:n}),_null:c("null",{startsExpr:n}),_true:c("true",{startsExpr:n}),_false:c("false",{startsExpr:n}),_in:c("in",{beforeExpr:r,binop:7}),_instanceof:c("instanceof",{beforeExpr:r,binop:7}),_typeof:c("typeof",{beforeExpr:r,prefix:o,startsExpr:n}),_void:c("void",{beforeExpr:r,prefix:o,startsExpr:n}),_delete:c("delete",{beforeExpr:r,prefix:o,startsExpr:n})},f=/\r\n?|[\n\u2028\u2029]/,d=new RegExp(f.source,"g");function h(e){switch(e){case 10:case 13:case 8232:case 8233:return!0;default:return!1}}const m=/(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g;function y(e){switch(e){case 9:case 11:case 12:case 32:case 160:case 5760:case 8192:case 8193:case 8194:case 8195:case 8196:case 8197:case 8198:case 8199:case 8200:case 8201:case 8202:case 8239:case 8287:case 12288:case 65279:return!0;default:return!1}}class g{constructor(e,t){this.line=void 0,this.column=void 0,this.line=e,this.column=t}}class b{constructor(e,t){this.start=void 0,this.end=void 0,this.filename=void 0,this.identifierName=void 0,this.start=e,this.end=t}}function v(e){return e[e.length-1]}const E=Object.freeze({SyntaxError:"BABEL_PARSER_SYNTAX_ERROR",SourceTypeModuleError:"BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED"}),x=T({AccessorIsGenerator:"A %0ter cannot be a generator.",ArgumentsInClass:"'arguments' is only allowed in functions and class methods.",AsyncFunctionInSingleStatementContext:"Async functions can only be declared at the top level or inside a block.",AwaitBindingIdentifier:"Can not use 'await' as identifier inside an async function.",AwaitBindingIdentifierInStaticBlock:"Can not use 'await' as identifier inside a static block.",AwaitExpressionFormalParameter:"'await' is not allowed in async function parameters.",AwaitNotInAsyncContext:"'await' is only allowed within async functions and at the top levels of modules.",AwaitNotInAsyncFunction:"'await' is only allowed within async functions.",BadGetterArity:"A 'get' accesor must not have any formal parameters.",BadSetterArity:"A 'set' accesor must have exactly one formal parameter.",BadSetterRestParameter:"A 'set' accesor function argument must not be a rest parameter.",ConstructorClassField:"Classes may not have a field named 'constructor'.",ConstructorClassPrivateField:"Classes may not have a private field named '#constructor'.",ConstructorIsAccessor:"Class constructor may not be an accessor.",ConstructorIsAsync:"Constructor can't be an async function.",ConstructorIsGenerator:"Constructor can't be a generator.",DeclarationMissingInitializer:"'%0' require an initialization value.",DecoratorBeforeExport:"Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax.",DecoratorConstructor:"Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?",DecoratorExportClass:"Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.",DecoratorSemicolon:"Decorators must not be followed by a semicolon.",DecoratorStaticBlock:"Decorators can't be used with a static block.",DeletePrivateField:"Deleting a private field is not allowed.",DestructureNamedImport:"ES2015 named imports do not destructure. Use another statement for destructuring after the import.",DuplicateConstructor:"Duplicate constructor in the same class.",DuplicateDefaultExport:"Only one default export allowed per module.",DuplicateExport:"`%0` has already been exported. Exported identifiers must be unique.",DuplicateProto:"Redefinition of __proto__ property.",DuplicateRegExpFlags:"Duplicate regular expression flag.",ElementAfterRest:"Rest element must be last element.",EscapedCharNotAnIdentifier:"Invalid Unicode escape.",ExportBindingIsString:"A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '%0' as '%1' } from 'some-module'`?",ExportDefaultFromAsIdentifier:"'from' is not allowed as an identifier after 'export default'.",ForInOfLoopInitializer:"'%0' loop variable declaration may not have an initializer.",ForOfAsync:"The left-hand side of a for-of loop may not be 'async'.",ForOfLet:"The left-hand side of a for-of loop may not start with 'let'.",GeneratorInSingleStatementContext:"Generators can only be declared at the top level or inside a block.",IllegalBreakContinue:"Unsyntactic %0.",IllegalLanguageModeDirective:"Illegal 'use strict' directive in function with non-simple parameter list.",IllegalReturn:"'return' outside of function.",ImportBindingIsString:'A string literal cannot be used as an imported binding.\n- Did you mean `import { "%0" as foo }`?',ImportCallArgumentTrailingComma:"Trailing comma is disallowed inside import(...) arguments.",ImportCallArity:"`import()` requires exactly %0.",ImportCallNotNewExpression:"Cannot use new with import(...).",ImportCallSpreadArgument:"`...` is not allowed in `import()`.",InvalidBigIntLiteral:"Invalid BigIntLiteral.",InvalidCodePoint:"Code point out of bounds.",InvalidDecimal:"Invalid decimal.",InvalidDigit:"Expected number in radix %0.",InvalidEscapeSequence:"Bad character escape sequence.",InvalidEscapeSequenceTemplate:"Invalid escape sequence in template.",InvalidEscapedReservedWord:"Escape sequence in keyword %0.",InvalidIdentifier:"Invalid identifier %0.",InvalidLhs:"Invalid left-hand side in %0.",InvalidLhsBinding:"Binding invalid left-hand side in %0.",InvalidNumber:"Invalid number.",InvalidOrMissingExponent:"Floating-point numbers require a valid exponent after the 'e'.",InvalidOrUnexpectedToken:"Unexpected character '%0'.",InvalidParenthesizedAssignment:"Invalid parenthesized assignment pattern.",InvalidPrivateFieldResolution:"Private name #%0 is not defined.",InvalidPropertyBindingPattern:"Binding member expression.",InvalidRecordProperty:"Only properties and spread elements are allowed in record definitions.",InvalidRestAssignmentPattern:"Invalid rest operator's argument.",LabelRedeclaration:"Label '%0' is already declared.",LetInLexicalBinding:"'let' is not allowed to be used as a name in 'let' or 'const' declarations.",LineTerminatorBeforeArrow:"No line break is allowed before '=>'.",MalformedRegExpFlags:"Invalid regular expression flag.",MissingClassName:"A class name is required.",MissingEqInAssignment:"Only '=' operator can be used for specifying default value.",MissingSemicolon:"Missing semicolon.",MissingUnicodeEscape:"Expecting Unicode escape sequence \\uXXXX.",MixingCoalesceWithLogical:"Nullish coalescing operator(??) requires parens when mixing with logical operators.",ModuleAttributeDifferentFromType:"The only accepted module attribute is `type`.",ModuleAttributeInvalidValue:"Only string literals are allowed as module attribute values.",ModuleAttributesWithDuplicateKeys:'Duplicate key "%0" is not allowed in module attributes.',ModuleExportNameHasLoneSurrogate:"An export name cannot include a lone surrogate, found '\\u%0'.",ModuleExportUndefined:"Export '%0' is not defined.",MultipleDefaultsInSwitch:"Multiple default clauses.",NewlineAfterThrow:"Illegal newline after throw.",NoCatchOrFinally:"Missing catch or finally clause.",NumberIdentifier:"Identifier directly after number.",NumericSeparatorInEscapeSequence:"Numeric separators are not allowed inside unicode escape sequences or hex escape sequences.",ObsoleteAwaitStar:"'await*' has been removed from the async functions proposal. Use Promise.all() instead.",OptionalChainingNoNew:"Constructors in/after an Optional Chain are not allowed.",OptionalChainingNoTemplate:"Tagged Template Literals are not allowed in optionalChain.",OverrideOnConstructor:"'override' modifier cannot appear on a constructor declaration.",ParamDupe:"Argument name clash.",PatternHasAccessor:"Object pattern can't contain getter or setter.",PatternHasMethod:"Object pattern can't contain methods.",PipelineBodyNoArrow:'Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized.',PipelineBodySequenceExpression:"Pipeline body may not be a comma-separated sequence expression.",PipelineHeadSequenceExpression:"Pipeline head should not be a comma-separated sequence expression.",PipelineTopicUnused:"Pipeline is in topic style but does not use topic reference.",PrimaryTopicNotAllowed:"Topic reference was used in a lexical context without topic binding.",PrimaryTopicRequiresSmartPipeline:"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.",PrivateInExpectedIn:"Private names are only allowed in property accesses (`obj.#%0`) or in `in` expressions (`#%0 in obj`).",PrivateNameRedeclaration:"Duplicate private name #%0.",RecordExpressionBarIncorrectEndSyntaxType:"Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.",RecordExpressionBarIncorrectStartSyntaxType:"Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.",RecordExpressionHashIncorrectStartSyntaxType:"Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'.",RecordNoProto:"'__proto__' is not allowed in Record expressions.",RestTrailingComma:"Unexpected trailing comma after rest element.",SloppyFunction:"In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement.",StaticPrototype:"Classes may not have static property named prototype.",StrictDelete:"Deleting local variable in strict mode.",StrictEvalArguments:"Assigning to '%0' in strict mode.",StrictEvalArgumentsBinding:"Binding '%0' in strict mode.",StrictFunction:"In strict mode code, functions can only be declared at top level or inside a block.",StrictNumericEscape:"The only valid numeric escape in strict mode is '\\0'.",StrictOctalLiteral:"Legacy octal literals are not allowed in strict mode.",StrictWith:"'with' in strict mode.",SuperNotAllowed:"`super()` is only valid inside a class constructor of a subclass. Maybe a typo in the method name ('constructor') or not extending another class?",SuperPrivateField:"Private fields can't be accessed on super.",TrailingDecorator:"Decorators must be attached to a class element.",TupleExpressionBarIncorrectEndSyntaxType:"Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.",TupleExpressionBarIncorrectStartSyntaxType:"Tuple expressions starting with '[|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.",TupleExpressionHashIncorrectStartSyntaxType:"Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'.",UnexpectedArgumentPlaceholder:"Unexpected argument placeholder.",UnexpectedAwaitAfterPipelineBody:'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal.',UnexpectedDigitAfterHash:"Unexpected digit after hash token.",UnexpectedImportExport:"'import' and 'export' may only appear at the top level.",UnexpectedKeyword:"Unexpected keyword '%0'.",UnexpectedLeadingDecorator:"Leading decorators must be attached to a class declaration.",UnexpectedLexicalDeclaration:"Lexical declaration cannot appear in a single-statement context.",UnexpectedNewTarget:"`new.target` can only be used in functions or class properties.",UnexpectedNumericSeparator:"A numeric separator is only allowed between two digits.",UnexpectedPrivateField:"Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p).",UnexpectedReservedWord:"Unexpected reserved word '%0'.",UnexpectedSuper:"'super' is only allowed in object methods and classes.",UnexpectedToken:"Unexpected token '%0'.",UnexpectedTokenUnaryExponentiation:"Illegal expression. Wrap left hand side or entire exponentiation in parentheses.",UnsupportedBind:"Binding should be performed on object property.",UnsupportedDecoratorExport:"A decorated export must export a class declaration.",UnsupportedDefaultExport:"Only expressions, functions or classes are allowed as the `default` export.",UnsupportedImport:"`import` can only be used in `import()` or `import.meta`.",UnsupportedMetaProperty:"The only valid meta property for %0 is %0.%1.",UnsupportedParameterDecorator:"Decorators cannot be used to decorate parameters.",UnsupportedPropertyDecorator:"Decorators cannot be used to decorate object literal properties.",UnsupportedSuper:"'super' can only be used with function calls (i.e. super()) or in property accesses (i.e. super.prop or super[prop]).",UnterminatedComment:"Unterminated comment.",UnterminatedRegExp:"Unterminated regular expression.",UnterminatedString:"Unterminated string constant.",UnterminatedTemplate:"Unterminated template.",VarRedeclaration:"Identifier '%0' has already been declared.",YieldBindingIdentifier:"Can not use 'yield' as identifier inside a generator.",YieldInParameter:"Yield expression is not allowed in formal parameters.",ZeroDigitNumericSeparator:"Numeric separator can not be used after leading 0."},E.SyntaxError),S=T({ImportMetaOutsideModule:"import.meta may appear only with 'sourceType: \"module\"'",ImportOutsideModule:"'import' and 'export' may appear only with 'sourceType: \"module\"'"},E.SourceTypeModuleError);function T(e,t){const r={};return Object.keys(e).forEach((n=>{r[n]=Object.freeze({code:t,reasonCode:n,template:e[n]})})),Object.freeze(r)}class w{constructor(e,t){this.token=void 0,this.preserveSpace=void 0,this.token=e,this.preserveSpace=!!t}}const P={brace:new w("{"),template:new w("`",!0)};p.braceR.updateContext=e=>{e.pop()},p.braceL.updateContext=p.braceHashL.updateContext=p.dollarBraceL.updateContext=e=>{e.push(P.brace)},p.backQuote.updateContext=e=>{e[e.length-1]===P.template?e.pop():e.push(P.template)};let A="ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙՠ-ֈא-תׯ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࡠ-ࡪࢠ-ࢴࢶ-ࣇऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱৼਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡૹଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘ-ౚౠౡಀಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഄ-ഌഎ-ഐഒ-ഺഽൎൔ-ൖൟ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄຆ-ຊຌ-ຣລວ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡸᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᲀ-ᲈᲐ-ᲺᲽ-Ჿᳩ-ᳬᳮ-ᳳᳵᳶᳺᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄯㄱ-ㆎㆠ-ㆿㇰ-ㇿ㐀-䶿一-鿼ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞿꟂ-ꟊꟵ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꣽꣾꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭩꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ",O="‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍୕-ୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఄా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ඁ-ඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᪿᫀᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧ꠬ꢀꢁꢴ-ꣅ꣐-꣙꣠-꣱ꣿ-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︯︳︴﹍-﹏0-9_";const C=new RegExp("["+A+"]"),I=new RegExp("["+A+O+"]");A=O=null;const k=[0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,349,41,7,1,79,28,11,0,9,21,107,20,28,22,13,52,76,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,230,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,190,0,80,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,43,8,8952,286,50,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,2357,44,11,6,17,0,370,43,1301,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42717,35,4148,12,221,3,5761,15,7472,3104,541,1507,4938],N=[509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,370,1,154,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1014,0,2,54,8,3,82,0,12,1,19628,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,419,13,1495,6,110,6,6,9,4759,9,787719,239];function _(e,t){let r=65536;for(let n=0,s=t.length;ne)return!1;if(r+=t[n+1],r>=e)return!0}return!1}function j(e){return e<65?36===e:e<=90||(e<97?95===e:e<=122||(e<=65535?e>=170&&C.test(String.fromCharCode(e)):_(e,k)))}function D(e){return e<48?36===e:e<58||!(e<65)&&(e<=90||(e<97?95===e:e<=122||(e<=65535?e>=170&&I.test(String.fromCharCode(e)):_(e,k)||_(e,N))))}const L=new Set(["break","case","catch","continue","debugger","default","do","else","finally","for","function","if","return","switch","throw","try","var","const","while","with","new","this","super","class","extends","export","import","null","true","false","in","instanceof","typeof","void","delete"]),M=new Set(["implements","interface","let","package","private","protected","public","static","yield"]),B=new Set(["eval","arguments"]);function R(e,t){return t&&"await"===e||"enum"===e}function F(e,t){return R(e,t)||M.has(e)}function U(e){return B.has(e)}function $(e,t){return F(e,t)||U(e)}function q(e){return L.has(e)}const V=new Set(["break","case","catch","continue","debugger","default","do","else","finally","for","function","if","return","switch","throw","try","var","const","while","with","new","this","super","class","extends","export","import","null","true","false","in","instanceof","typeof","void","delete","implements","interface","let","package","private","protected","public","static","yield","eval","arguments","enum","await"]);class W{constructor(e){this.var=new Set,this.lexical=new Set,this.functions=new Set,this.flags=e}}class K{constructor(e,t){this.scopeStack=[],this.undefinedExports=new Map,this.undefinedPrivateNames=new Map,this.raise=e,this.inModule=t}get inFunction(){return(2&this.currentVarScopeFlags())>0}get allowSuper(){return(16&this.currentThisScopeFlags())>0}get allowDirectSuper(){return(32&this.currentThisScopeFlags())>0}get inClass(){return(64&this.currentThisScopeFlags())>0}get inClassAndNotInNonArrowFunction(){const e=this.currentThisScopeFlags();return(64&e)>0&&0==(2&e)}get inStaticBlock(){return(128&this.currentThisScopeFlags())>0}get inNonArrowFunction(){return(2&this.currentThisScopeFlags())>0}get treatFunctionsAsVar(){return this.treatFunctionsAsVarInScope(this.currentScope())}createScope(e){return new W(e)}enter(e){this.scopeStack.push(this.createScope(e))}exit(){this.scopeStack.pop()}treatFunctionsAsVarInScope(e){return!!(2&e.flags||!this.inModule&&1&e.flags)}declareName(e,t,r){let n=this.currentScope();if(8&t||16&t)this.checkRedeclarationInScope(n,e,t,r),16&t?n.functions.add(e):n.lexical.add(e),8&t&&this.maybeExportDefined(n,e);else if(4&t)for(let s=this.scopeStack.length-1;s>=0&&(n=this.scopeStack[s],this.checkRedeclarationInScope(n,e,t,r),n.var.add(e),this.maybeExportDefined(n,e),!(259&n.flags));--s);this.inModule&&1&n.flags&&this.undefinedExports.delete(e)}maybeExportDefined(e,t){this.inModule&&1&e.flags&&this.undefinedExports.delete(t)}checkRedeclarationInScope(e,t,r,n){this.isRedeclaredInScope(e,t,r)&&this.raise(n,x.VarRedeclaration,t)}isRedeclaredInScope(e,t,r){return!!(1&r)&&(8&r?e.lexical.has(t)||e.functions.has(t)||e.var.has(t):16&r?e.lexical.has(t)||!this.treatFunctionsAsVarInScope(e)&&e.var.has(t):e.lexical.has(t)&&!(8&e.flags&&e.lexical.values().next().value===t)||!this.treatFunctionsAsVarInScope(e)&&e.functions.has(t))}checkLocalExport(e){const{name:t}=e,r=this.scopeStack[0];r.lexical.has(t)||r.var.has(t)||r.functions.has(t)||this.undefinedExports.set(t,e.start)}currentScope(){return this.scopeStack[this.scopeStack.length-1]}currentVarScopeFlags(){for(let e=this.scopeStack.length-1;;e--){const{flags:t}=this.scopeStack[e];if(259&t)return t}}currentThisScopeFlags(){for(let e=this.scopeStack.length-1;;e--){const{flags:t}=this.scopeStack[e];if(323&t&&!(4&t))return t}}}class G extends W{constructor(...e){super(...e),this.declareFunctions=new Set}}class H extends K{createScope(e){return new G(e)}declareName(e,t,r){const n=this.currentScope();if(2048&t)return this.checkRedeclarationInScope(n,e,t,r),this.maybeExportDefined(n,e),void n.declareFunctions.add(e);super.declareName(...arguments)}isRedeclaredInScope(e,t,r){return!!super.isRedeclaredInScope(...arguments)||!!(2048&r)&&!e.declareFunctions.has(t)&&(e.lexical.has(t)||e.functions.has(t))}checkLocalExport(e){this.scopeStack[0].declareFunctions.has(e.name)||super.checkLocalExport(e)}}const J=new Set(["_","any","bool","boolean","empty","extends","false","interface","mixed","null","number","static","string","true","typeof","void"]),Y=T({AmbiguousConditionalArrow:"Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.",AmbiguousDeclareModuleKind:"Found both `declare module.exports` and `declare export` in the same module. Modules can only have 1 since they are either an ES module or they are a CommonJS module.",AssignReservedType:"Cannot overwrite reserved type %0.",DeclareClassElement:"The `declare` modifier can only appear on class fields.",DeclareClassFieldInitializer:"Initializers are not allowed in fields with the `declare` modifier.",DuplicateDeclareModuleExports:"Duplicate `declare module.exports` statement.",EnumBooleanMemberNotInitialized:"Boolean enum members need to be initialized. Use either `%0 = true,` or `%0 = false,` in enum `%1`.",EnumDuplicateMemberName:"Enum member names need to be unique, but the name `%0` has already been used before in enum `%1`.",EnumInconsistentMemberValues:"Enum `%0` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.",EnumInvalidExplicitType:"Enum type `%1` is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",EnumInvalidExplicitTypeUnknownSupplied:"Supplied enum type is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",EnumInvalidMemberInitializerPrimaryType:"Enum `%0` has type `%2`, so the initializer of `%1` needs to be a %2 literal.",EnumInvalidMemberInitializerSymbolType:"Symbol enum members cannot be initialized. Use `%1,` in enum `%0`.",EnumInvalidMemberInitializerUnknownType:"The enum member initializer for `%1` needs to be a literal (either a boolean, number, or string) in enum `%0`.",EnumInvalidMemberName:"Enum member names cannot start with lowercase 'a' through 'z'. Instead of using `%0`, consider using `%1`, in enum `%2`.",EnumNumberMemberNotInitialized:"Number enum members need to be initialized, e.g. `%1 = 1` in enum `%0`.",EnumStringMemberInconsistentlyInitailized:"String enum members need to consistently either all use initializers, or use no initializers, in enum `%0`.",GetterMayNotHaveThisParam:"A getter cannot have a `this` parameter.",ImportTypeShorthandOnlyInPureImport:"The `type` and `typeof` keywords on named imports can only be used on regular `import` statements. It cannot be used with `import type` or `import typeof` statements.",InexactInsideExact:"Explicit inexact syntax cannot appear inside an explicit exact object type.",InexactInsideNonObject:"Explicit inexact syntax cannot appear in class or interface definitions.",InexactVariance:"Explicit inexact syntax cannot have variance.",InvalidNonTypeImportInDeclareModule:"Imports within a `declare module` body must always be `import type` or `import typeof`.",MissingTypeParamDefault:"Type parameter declaration needs a default, since a preceding type parameter declaration has a default.",NestedDeclareModule:"`declare module` cannot be used inside another `declare module`.",NestedFlowComment:"Cannot have a flow comment inside another flow comment.",OptionalBindingPattern:"A binding pattern parameter cannot be optional in an implementation signature.",SetterMayNotHaveThisParam:"A setter cannot have a `this` parameter.",SpreadVariance:"Spread properties cannot have variance.",ThisParamAnnotationRequired:"A type annotation is required for the `this` parameter.",ThisParamBannedInConstructor:"Constructors cannot have a `this` parameter; constructors don't bind `this` like other functions.",ThisParamMayNotBeOptional:"The `this` parameter cannot be optional.",ThisParamMustBeFirst:"The `this` parameter must be the first function parameter.",ThisParamNoDefault:"The `this` parameter may not have a default value.",TypeBeforeInitializer:"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.",TypeCastInPattern:"The type cast expression is expected to be wrapped with parenthesis.",UnexpectedExplicitInexactInObject:"Explicit inexact syntax must appear at the end of an inexact object.",UnexpectedReservedType:"Unexpected reserved type %0.",UnexpectedReservedUnderscore:"`_` is only allowed as a type argument to call or new.",UnexpectedSpaceBetweenModuloChecks:"Spaces between `%` and `checks` are not allowed here.",UnexpectedSpreadType:"Spread operator cannot appear in class or interface definitions.",UnexpectedSubtractionOperand:'Unexpected token, expected "number" or "bigint".',UnexpectedTokenAfterTypeParameter:"Expected an arrow function after this type parameter declaration.",UnexpectedTypeParameterBeforeAsyncArrowFunction:"Type parameters must come after the async keyword, e.g. instead of ` async () => {}`, use `async () => {}`.",UnsupportedDeclareExportKind:"`declare export %0` is not supported. Use `%1` instead.",UnsupportedStatementInDeclareModule:"Only declares and type imports are allowed inside declare module.",UnterminatedFlowComment:"Unterminated flow-comment."},E.SyntaxError);function X(e){return"type"===e.importKind||"typeof"===e.importKind}function z(e){return(e.type===p.name||!!e.type.keyword)&&"from"!==e.value}const Q={const:"declare export var",let:"declare export var",type:"export type",interface:"export interface"},Z=/\*?\s*@((?:no)?flow)\b/,ee={quot:'"',amp:"&",apos:"'",lt:"<",gt:">",nbsp:" ",iexcl:"¡",cent:"¢",pound:"£",curren:"¤",yen:"¥",brvbar:"¦",sect:"§",uml:"¨",copy:"©",ordf:"ª",laquo:"«",not:"¬",shy:"­",reg:"®",macr:"¯",deg:"°",plusmn:"±",sup2:"²",sup3:"³",acute:"´",micro:"µ",para:"¶",middot:"·",cedil:"¸",sup1:"¹",ordm:"º",raquo:"»",frac14:"¼",frac12:"½",frac34:"¾",iquest:"¿",Agrave:"À",Aacute:"Á",Acirc:"Â",Atilde:"Ã",Auml:"Ä",Aring:"Å",AElig:"Æ",Ccedil:"Ç",Egrave:"È",Eacute:"É",Ecirc:"Ê",Euml:"Ë",Igrave:"Ì",Iacute:"Í",Icirc:"Î",Iuml:"Ï",ETH:"Ð",Ntilde:"Ñ",Ograve:"Ò",Oacute:"Ó",Ocirc:"Ô",Otilde:"Õ",Ouml:"Ö",times:"×",Oslash:"Ø",Ugrave:"Ù",Uacute:"Ú",Ucirc:"Û",Uuml:"Ü",Yacute:"Ý",THORN:"Þ",szlig:"ß",agrave:"à",aacute:"á",acirc:"â",atilde:"ã",auml:"ä",aring:"å",aelig:"æ",ccedil:"ç",egrave:"è",eacute:"é",ecirc:"ê",euml:"ë",igrave:"ì",iacute:"í",icirc:"î",iuml:"ï",eth:"ð",ntilde:"ñ",ograve:"ò",oacute:"ó",ocirc:"ô",otilde:"õ",ouml:"ö",divide:"÷",oslash:"ø",ugrave:"ù",uacute:"ú",ucirc:"û",uuml:"ü",yacute:"ý",thorn:"þ",yuml:"ÿ",OElig:"Œ",oelig:"œ",Scaron:"Š",scaron:"š",Yuml:"Ÿ",fnof:"ƒ",circ:"ˆ",tilde:"˜",Alpha:"Α",Beta:"Β",Gamma:"Γ",Delta:"Δ",Epsilon:"Ε",Zeta:"Ζ",Eta:"Η",Theta:"Θ",Iota:"Ι",Kappa:"Κ",Lambda:"Λ",Mu:"Μ",Nu:"Ν",Xi:"Ξ",Omicron:"Ο",Pi:"Π",Rho:"Ρ",Sigma:"Σ",Tau:"Τ",Upsilon:"Υ",Phi:"Φ",Chi:"Χ",Psi:"Ψ",Omega:"Ω",alpha:"α",beta:"β",gamma:"γ",delta:"δ",epsilon:"ε",zeta:"ζ",eta:"η",theta:"θ",iota:"ι",kappa:"κ",lambda:"λ",mu:"μ",nu:"ν",xi:"ξ",omicron:"ο",pi:"π",rho:"ρ",sigmaf:"ς",sigma:"σ",tau:"τ",upsilon:"υ",phi:"φ",chi:"χ",psi:"ψ",omega:"ω",thetasym:"ϑ",upsih:"ϒ",piv:"ϖ",ensp:" ",emsp:" ",thinsp:" ",zwnj:"‌",zwj:"‍",lrm:"‎",rlm:"‏",ndash:"–",mdash:"—",lsquo:"‘",rsquo:"’",sbquo:"‚",ldquo:"“",rdquo:"”",bdquo:"„",dagger:"†",Dagger:"‡",bull:"•",hellip:"…",permil:"‰",prime:"′",Prime:"″",lsaquo:"‹",rsaquo:"›",oline:"‾",frasl:"⁄",euro:"€",image:"ℑ",weierp:"℘",real:"ℜ",trade:"™",alefsym:"ℵ",larr:"←",uarr:"↑",rarr:"→",darr:"↓",harr:"↔",crarr:"↵",lArr:"⇐",uArr:"⇑",rArr:"⇒",dArr:"⇓",hArr:"⇔",forall:"∀",part:"∂",exist:"∃",empty:"∅",nabla:"∇",isin:"∈",notin:"∉",ni:"∋",prod:"∏",sum:"∑",minus:"−",lowast:"∗",radic:"√",prop:"∝",infin:"∞",ang:"∠",and:"∧",or:"∨",cap:"∩",cup:"∪",int:"∫",there4:"∴",sim:"∼",cong:"≅",asymp:"≈",ne:"≠",equiv:"≡",le:"≤",ge:"≥",sub:"⊂",sup:"⊃",nsub:"⊄",sube:"⊆",supe:"⊇",oplus:"⊕",otimes:"⊗",perp:"⊥",sdot:"⋅",lceil:"⌈",rceil:"⌉",lfloor:"⌊",rfloor:"⌋",lang:"〈",rang:"〉",loz:"◊",spades:"♠",clubs:"♣",hearts:"♥",diams:"♦"};class te{constructor(){this.strict=void 0,this.curLine=void 0,this.startLoc=void 0,this.endLoc=void 0,this.errors=[],this.potentialArrowAt=-1,this.noArrowAt=[],this.noArrowParamsConversionAt=[],this.maybeInArrowParameters=!1,this.inPipeline=!1,this.inType=!1,this.noAnonFunctionType=!1,this.inPropertyName=!1,this.hasFlowComment=!1,this.isAmbientContext=!1,this.inAbstractClass=!1,this.topicContext={maxNumOfResolvableTopics:0,maxTopicIndex:null},this.soloAwait=!1,this.inFSharpPipelineDirectBody=!1,this.labels=[],this.decoratorStack=[[]],this.comments=[],this.trailingComments=[],this.leadingComments=[],this.commentStack=[],this.commentPreviousNode=null,this.pos=0,this.lineStart=0,this.type=p.eof,this.value=null,this.start=0,this.end=0,this.lastTokEndLoc=null,this.lastTokStartLoc=null,this.lastTokStart=0,this.lastTokEnd=0,this.context=[P.brace],this.exprAllowed=!0,this.containsEsc=!1,this.strictErrors=new Map,this.tokensLength=0}init(e){this.strict=!1!==e.strictMode&&"module"===e.sourceType,this.curLine=e.startLine,this.startLoc=this.endLoc=this.curPosition()}curPosition(){return new g(this.curLine,this.pos-this.lineStart)}clone(e){const t=new te,r=Object.keys(this);for(let n=0,s=r.length;n.",MissingClosingTagFragment:"Expected corresponding JSX closing tag for <>.",UnexpectedSequenceExpression:"Sequence expressions cannot be directly nested inside JSX. Did you mean to wrap it in parentheses (...)?",UnsupportedJsxValue:"JSX value should be either an expression or a quoted JSX text.",UnterminatedJsxContent:"Unterminated JSX contents.",UnwrappedAdjacentJSXElements:"Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?"},E.SyntaxError);function ie(e){return!!e&&("JSXOpeningFragment"===e.type||"JSXClosingFragment"===e.type)}function oe(e){if("JSXIdentifier"===e.type)return e.name;if("JSXNamespacedName"===e.type)return e.namespace.name+":"+e.name.name;if("JSXMemberExpression"===e.type)return oe(e.object)+"."+oe(e.property);throw new Error("Node had unexpected type: "+e.type)}P.j_oTag=new w("...",!0),p.jsxName=new a("jsxName"),p.jsxText=new a("jsxText",{beforeExpr:!0}),p.jsxTagStart=new a("jsxTagStart",{startsExpr:!0}),p.jsxTagEnd=new a("jsxTagEnd"),p.jsxTagStart.updateContext=e=>{e.push(P.j_expr,P.j_oTag)};class ae extends W{constructor(...e){super(...e),this.types=new Set,this.enums=new Set,this.constEnums=new Set,this.classes=new Set,this.exportOnlyBindings=new Set}}class le extends K{createScope(e){return new ae(e)}declareName(e,t,r){const n=this.currentScope();if(1024&t)return this.maybeExportDefined(n,e),void n.exportOnlyBindings.add(e);super.declareName(...arguments),2&t&&(1&t||(this.checkRedeclarationInScope(n,e,t,r),this.maybeExportDefined(n,e)),n.types.add(e)),256&t&&n.enums.add(e),512&t&&n.constEnums.add(e),128&t&&n.classes.add(e)}isRedeclaredInScope(e,t,r){return e.enums.has(t)?!(256&r)||!!(512&r)!==e.constEnums.has(t):128&r&&e.classes.has(t)?!!e.lexical.has(t)&&!!(1&r):!!(2&r&&e.types.has(t))||super.isRedeclaredInScope(...arguments)}checkLocalExport(e){const t=this.scopeStack[0],{name:r}=e;t.types.has(r)||t.exportOnlyBindings.has(r)||super.checkLocalExport(e)}}class ce{constructor(){this.stacks=[]}enter(e){this.stacks.push(e)}exit(){this.stacks.pop()}currentFlags(){return this.stacks[this.stacks.length-1]}get hasAwait(){return(2&this.currentFlags())>0}get hasYield(){return(1&this.currentFlags())>0}get hasReturn(){return(4&this.currentFlags())>0}get hasIn(){return(8&this.currentFlags())>0}}function ue(e,t){return(e?2:0)|(t?1:0)}function pe(e){if(null==e)throw new Error(`Unexpected ${e} value.`);return e}function fe(e){if(!e)throw new Error("Assert fail")}const de=T({AbstractMethodHasImplementation:"Method '%0' cannot have an implementation because it is marked abstract.",AccesorCannotDeclareThisParameter:"'get' and 'set' accessors cannot declare 'this' parameters.",AccesorCannotHaveTypeParameters:"An accessor cannot have type parameters.",ClassMethodHasDeclare:"Class methods cannot have the 'declare' modifier.",ClassMethodHasReadonly:"Class methods cannot have the 'readonly' modifier.",ConstructorHasTypeParameters:"Type parameters cannot appear on a constructor declaration.",DeclareAccessor:"'declare' is not allowed in %0ters.",DeclareClassFieldHasInitializer:"Initializers are not allowed in ambient contexts.",DeclareFunctionHasImplementation:"An implementation cannot be declared in ambient contexts.",DuplicateAccessibilityModifier:"Accessibility modifier already seen.",DuplicateModifier:"Duplicate modifier: '%0'.",EmptyHeritageClauseType:"'%0' list cannot be empty.",EmptyTypeArguments:"Type argument list cannot be empty.",EmptyTypeParameters:"Type parameter list cannot be empty.",ExpectedAmbientAfterExportDeclare:"'export declare' must be followed by an ambient declaration.",ImportAliasHasImportType:"An import alias can not use 'import type'.",IncompatibleModifiers:"'%0' modifier cannot be used with '%1' modifier.",IndexSignatureHasAbstract:"Index signatures cannot have the 'abstract' modifier.",IndexSignatureHasAccessibility:"Index signatures cannot have an accessibility modifier ('%0').",IndexSignatureHasDeclare:"Index signatures cannot have the 'declare' modifier.",IndexSignatureHasOverride:"'override' modifier cannot appear on an index signature.",IndexSignatureHasStatic:"Index signatures cannot have the 'static' modifier.",InvalidModifierOnTypeMember:"'%0' modifier cannot appear on a type member.",InvalidModifiersOrder:"'%0' modifier must precede '%1' modifier.",InvalidTupleMemberLabel:"Tuple members must be labeled with a simple identifier.",MixedLabeledAndUnlabeledElements:"Tuple members must all have names or all not have names.",NonAbstractClassHasAbstractMethod:"Abstract methods can only appear within an abstract class.",NonClassMethodPropertyHasAbstractModifer:"'abstract' modifier can only appear on a class, method, or property declaration.",OptionalTypeBeforeRequired:"A required element cannot follow an optional element.",OverrideNotInSubClass:"This member cannot have an 'override' modifier because its containing class does not extend another class.",PatternIsOptional:"A binding pattern parameter cannot be optional in an implementation signature.",PrivateElementHasAbstract:"Private elements cannot have the 'abstract' modifier.",PrivateElementHasAccessibility:"Private elements cannot have an accessibility modifier ('%0').",ReadonlyForMethodSignature:"'readonly' modifier can only appear on a property declaration or index signature.",SetAccesorCannotHaveOptionalParameter:"A 'set' accessor cannot have an optional parameter.",SetAccesorCannotHaveRestParameter:"A 'set' accessor cannot have rest parameter.",SetAccesorCannotHaveReturnType:"A 'set' accessor cannot have a return type annotation.",StaticBlockCannotHaveModifier:"Static class blocks cannot have any modifier.",TypeAnnotationAfterAssign:"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.",TypeImportCannotSpecifyDefaultAndNamed:"A type-only import can specify a default import or named bindings, but not both.",UnexpectedParameterModifier:"A parameter property is only allowed in a constructor implementation.",UnexpectedReadonly:"'readonly' type modifier is only permitted on array and tuple literal types.",UnexpectedTypeAnnotation:"Did not expect a type annotation here.",UnexpectedTypeCastInParameter:"Unexpected type cast in parameter position.",UnsupportedImportTypeArgument:"Argument in a type import must be a string literal.",UnsupportedParameterPropertyKind:"A parameter property may not be declared using a binding pattern.",UnsupportedSignatureParameterKind:"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0."},E.SyntaxError);function he(e){return"private"===e||"public"===e||"protected"===e}p.placeholder=new a("%%",{startsExpr:!0});const me=T({ClassNameIsRequired:"A class name is required."},E.SyntaxError);function ye(e,t){return e.some((e=>Array.isArray(e)?e[0]===t:e===t))}function ge(e,t,r){const n=e.find((e=>Array.isArray(e)?e[0]===t:e===t));return n&&Array.isArray(n)?n[1][r]:null}const be=["minimal","smart","fsharp"],ve=["hash","bar"],Ee={estree:e=>class extends e{parseRegExpLiteral({pattern:e,flags:t}){let r=null;try{r=new RegExp(e,t)}catch(e){}const n=this.estreeParseLiteral(r);return n.regex={pattern:e,flags:t},n}parseBigIntLiteral(e){let t;try{t=BigInt(e)}catch(e){t=null}const r=this.estreeParseLiteral(t);return r.bigint=String(r.value||e),r}parseDecimalLiteral(e){const t=this.estreeParseLiteral(null);return t.decimal=String(t.value||e),t}estreeParseLiteral(e){return this.parseLiteral(e,"Literal")}parseStringLiteral(e){return this.estreeParseLiteral(e)}parseNumericLiteral(e){return this.estreeParseLiteral(e)}parseNullLiteral(){return this.estreeParseLiteral(null)}parseBooleanLiteral(e){return this.estreeParseLiteral(e)}directiveToStmt(e){const t=e.value,r=this.startNodeAt(e.start,e.loc.start),n=this.startNodeAt(t.start,t.loc.start);return n.value=t.extra.expressionValue,n.raw=t.extra.raw,r.expression=this.finishNodeAt(n,"Literal",t.end,t.loc.end),r.directive=t.extra.raw.slice(1,-1),this.finishNodeAt(r,"ExpressionStatement",e.end,e.loc.end)}initFunction(e,t){super.initFunction(e,t),e.expression=!1}checkDeclaration(e){null!=e&&this.isObjectProperty(e)?this.checkDeclaration(e.value):super.checkDeclaration(e)}getObjectOrClassMethodParams(e){return e.value.params}isValidDirective(e){var t;return"ExpressionStatement"===e.type&&"Literal"===e.expression.type&&"string"==typeof e.expression.value&&!(null!=(t=e.expression.extra)&&t.parenthesized)}stmtToDirective(e){const t=super.stmtToDirective(e),r=e.expression.value;return this.addExtra(t.value,"expressionValue",r),t}parseBlockBody(e,...t){super.parseBlockBody(e,...t);const r=e.directives.map((e=>this.directiveToStmt(e)));e.body=r.concat(e.body),delete e.directives}pushClassMethod(e,t,r,n,s,i){this.parseMethod(t,r,n,s,i,"ClassMethod",!0),t.typeParameters&&(t.value.typeParameters=t.typeParameters,delete t.typeParameters),e.body.push(t)}parseMaybePrivateName(...e){const t=super.parseMaybePrivateName(...e);return"PrivateName"===t.type&&this.getPluginOption("estree","classFeatures")?this.convertPrivateNameToPrivateIdentifier(t):t}convertPrivateNameToPrivateIdentifier(e){const t=super.getPrivateNameSV(e);return delete(e=e).id,e.name=t,e.type="PrivateIdentifier",e}isPrivateName(e){return this.getPluginOption("estree","classFeatures")?"PrivateIdentifier"===e.type:super.isPrivateName(e)}getPrivateNameSV(e){return this.getPluginOption("estree","classFeatures")?e.name:super.getPrivateNameSV(e)}parseLiteral(e,t){const r=super.parseLiteral(e,t);return r.raw=r.extra.raw,delete r.extra,r}parseFunctionBody(e,t,r=!1){super.parseFunctionBody(e,t,r),e.expression="BlockStatement"!==e.body.type}parseMethod(e,t,r,n,s,i,o=!1){let a=this.startNode();return a.kind=e.kind,a=super.parseMethod(a,t,r,n,s,i,o),a.type="FunctionExpression",delete a.kind,e.value=a,"ClassPrivateMethod"===i&&(e.computed=!1),i="MethodDefinition",this.finishNode(e,i)}parseClassProperty(...e){const t=super.parseClassProperty(...e);return this.getPluginOption("estree","classFeatures")&&(t.type="PropertyDefinition"),t}parseClassPrivateProperty(...e){const t=super.parseClassPrivateProperty(...e);return this.getPluginOption("estree","classFeatures")&&(t.type="PropertyDefinition",t.computed=!1),t}parseObjectMethod(e,t,r,n,s){const i=super.parseObjectMethod(e,t,r,n,s);return i&&(i.type="Property","method"===i.kind&&(i.kind="init"),i.shorthand=!1),i}parseObjectProperty(e,t,r,n,s){const i=super.parseObjectProperty(e,t,r,n,s);return i&&(i.kind="init",i.type="Property"),i}toAssignable(e,t=!1){return null!=e&&this.isObjectProperty(e)?(this.toAssignable(e.value,t),e):super.toAssignable(e,t)}toAssignableObjectExpressionProp(e,...t){"get"===e.kind||"set"===e.kind?this.raise(e.key.start,x.PatternHasAccessor):e.method?this.raise(e.key.start,x.PatternHasMethod):super.toAssignableObjectExpressionProp(e,...t)}finishCallExpression(e,t){var r;(super.finishCallExpression(e,t),"Import"===e.callee.type)&&(e.type="ImportExpression",e.source=e.arguments[0],this.hasPlugin("importAssertions")&&(e.attributes=null!=(r=e.arguments[1])?r:null),delete e.arguments,delete e.callee);return e}toReferencedArguments(e){"ImportExpression"!==e.type&&super.toReferencedArguments(e)}parseExport(e){switch(super.parseExport(e),e.type){case"ExportAllDeclaration":e.exported=null;break;case"ExportNamedDeclaration":1===e.specifiers.length&&"ExportNamespaceSpecifier"===e.specifiers[0].type&&(e.type="ExportAllDeclaration",e.exported=e.specifiers[0].exported,delete e.specifiers)}return e}parseSubscript(e,t,r,n,s){const i=super.parseSubscript(e,t,r,n,s);if(s.optionalChainMember){if("OptionalMemberExpression"!==i.type&&"OptionalCallExpression"!==i.type||(i.type=i.type.substring(8)),s.stop){const e=this.startNodeAtNode(i);return e.expression=i,this.finishNode(e,"ChainExpression")}}else"MemberExpression"!==i.type&&"CallExpression"!==i.type||(i.optional=!1);return i}hasPropertyAsPrivateName(e){return"ChainExpression"===e.type&&(e=e.expression),super.hasPropertyAsPrivateName(e)}isOptionalChain(e){return"ChainExpression"===e.type}isObjectProperty(e){return"Property"===e.type&&"init"===e.kind&&!e.method}isObjectMethod(e){return e.method||"get"===e.kind||"set"===e.kind}},jsx:e=>class extends e{jsxReadToken(){let e="",t=this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,se.UnterminatedJsxContent);const r=this.input.charCodeAt(this.state.pos);switch(r){case 60:case 123:return this.state.pos===this.state.start?60===r&&this.state.exprAllowed?(++this.state.pos,this.finishToken(p.jsxTagStart)):super.getTokenFromCode(r):(e+=this.input.slice(t,this.state.pos),this.finishToken(p.jsxText,e));case 38:e+=this.input.slice(t,this.state.pos),e+=this.jsxReadEntity(),t=this.state.pos;break;case 62:case 125:default:h(r)?(e+=this.input.slice(t,this.state.pos),e+=this.jsxReadNewLine(!0),t=this.state.pos):++this.state.pos}}}jsxReadNewLine(e){const t=this.input.charCodeAt(this.state.pos);let r;return++this.state.pos,13===t&&10===this.input.charCodeAt(this.state.pos)?(++this.state.pos,r=e?"\n":"\r\n"):r=String.fromCharCode(t),++this.state.curLine,this.state.lineStart=this.state.pos,r}jsxReadString(e){let t="",r=++this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,x.UnterminatedString);const n=this.input.charCodeAt(this.state.pos);if(n===e)break;38===n?(t+=this.input.slice(r,this.state.pos),t+=this.jsxReadEntity(),r=this.state.pos):h(n)?(t+=this.input.slice(r,this.state.pos),t+=this.jsxReadNewLine(!1),r=this.state.pos):++this.state.pos}return t+=this.input.slice(r,this.state.pos++),this.finishToken(p.string,t)}jsxReadEntity(){let e,t="",r=0,n=this.input[this.state.pos];const s=++this.state.pos;for(;this.state.posclass extends e{constructor(...e){super(...e),this.flowPragma=void 0}getScopeHandler(){return H}shouldParseTypes(){return this.getPluginOption("flow","all")||"flow"===this.flowPragma}shouldParseEnums(){return!!this.getPluginOption("flow","enums")}finishToken(e,t){return e!==p.string&&e!==p.semi&&e!==p.interpreterDirective&&void 0===this.flowPragma&&(this.flowPragma=null),super.finishToken(e,t)}addComment(e){if(void 0===this.flowPragma){const t=Z.exec(e.value);if(t)if("flow"===t[1])this.flowPragma="flow";else{if("noflow"!==t[1])throw new Error("Unexpected flow pragma");this.flowPragma="noflow"}}return super.addComment(e)}flowParseTypeInitialiser(e){const t=this.state.inType;this.state.inType=!0,this.expect(e||p.colon);const r=this.flowParseType();return this.state.inType=t,r}flowParsePredicate(){const e=this.startNode(),t=this.state.start;return this.next(),this.expectContextual("checks"),this.state.lastTokStart>t+1&&this.raise(t,Y.UnexpectedSpaceBetweenModuloChecks),this.eat(p.parenL)?(e.value=this.parseExpression(),this.expect(p.parenR),this.finishNode(e,"DeclaredPredicate")):this.finishNode(e,"InferredPredicate")}flowParseTypeAndPredicateInitialiser(){const e=this.state.inType;this.state.inType=!0,this.expect(p.colon);let t=null,r=null;return this.match(p.modulo)?(this.state.inType=e,r=this.flowParsePredicate()):(t=this.flowParseType(),this.state.inType=e,this.match(p.modulo)&&(r=this.flowParsePredicate())),[t,r]}flowParseDeclareClass(e){return this.next(),this.flowParseInterfaceish(e,!0),this.finishNode(e,"DeclareClass")}flowParseDeclareFunction(e){this.next();const t=e.id=this.parseIdentifier(),r=this.startNode(),n=this.startNode();this.isRelational("<")?r.typeParameters=this.flowParseTypeParameterDeclaration():r.typeParameters=null,this.expect(p.parenL);const s=this.flowParseFunctionTypeParams();return r.params=s.params,r.rest=s.rest,r.this=s._this,this.expect(p.parenR),[r.returnType,e.predicate]=this.flowParseTypeAndPredicateInitialiser(),n.typeAnnotation=this.finishNode(r,"FunctionTypeAnnotation"),t.typeAnnotation=this.finishNode(n,"TypeAnnotation"),this.resetEndLocation(t),this.semicolon(),this.scope.declareName(e.id.name,2048,e.id.start),this.finishNode(e,"DeclareFunction")}flowParseDeclare(e,t){if(this.match(p._class))return this.flowParseDeclareClass(e);if(this.match(p._function))return this.flowParseDeclareFunction(e);if(this.match(p._var))return this.flowParseDeclareVariable(e);if(this.eatContextual("module"))return this.match(p.dot)?this.flowParseDeclareModuleExports(e):(t&&this.raise(this.state.lastTokStart,Y.NestedDeclareModule),this.flowParseDeclareModule(e));if(this.isContextual("type"))return this.flowParseDeclareTypeAlias(e);if(this.isContextual("opaque"))return this.flowParseDeclareOpaqueType(e);if(this.isContextual("interface"))return this.flowParseDeclareInterface(e);if(this.match(p._export))return this.flowParseDeclareExportDeclaration(e,t);throw this.unexpected()}flowParseDeclareVariable(e){return this.next(),e.id=this.flowParseTypeAnnotatableIdentifier(!0),this.scope.declareName(e.id.name,5,e.id.start),this.semicolon(),this.finishNode(e,"DeclareVariable")}flowParseDeclareModule(e){this.scope.enter(0),this.match(p.string)?e.id=this.parseExprAtom():e.id=this.parseIdentifier();const t=e.body=this.startNode(),r=t.body=[];for(this.expect(p.braceL);!this.match(p.braceR);){let e=this.startNode();this.match(p._import)?(this.next(),this.isContextual("type")||this.match(p._typeof)||this.raise(this.state.lastTokStart,Y.InvalidNonTypeImportInDeclareModule),this.parseImport(e)):(this.expectContextual("declare",Y.UnsupportedStatementInDeclareModule),e=this.flowParseDeclare(e,!0)),r.push(e)}this.scope.exit(),this.expect(p.braceR),this.finishNode(t,"BlockStatement");let n=null,s=!1;return r.forEach((e=>{!function(e){return"DeclareExportAllDeclaration"===e.type||"DeclareExportDeclaration"===e.type&&(!e.declaration||"TypeAlias"!==e.declaration.type&&"InterfaceDeclaration"!==e.declaration.type)}(e)?"DeclareModuleExports"===e.type&&(s&&this.raise(e.start,Y.DuplicateDeclareModuleExports),"ES"===n&&this.raise(e.start,Y.AmbiguousDeclareModuleKind),n="CommonJS",s=!0):("CommonJS"===n&&this.raise(e.start,Y.AmbiguousDeclareModuleKind),n="ES")})),e.kind=n||"CommonJS",this.finishNode(e,"DeclareModule")}flowParseDeclareExportDeclaration(e,t){if(this.expect(p._export),this.eat(p._default))return this.match(p._function)||this.match(p._class)?e.declaration=this.flowParseDeclare(this.startNode()):(e.declaration=this.flowParseType(),this.semicolon()),e.default=!0,this.finishNode(e,"DeclareExportDeclaration");if(this.match(p._const)||this.isLet()||(this.isContextual("type")||this.isContextual("interface"))&&!t){const e=this.state.value,t=Q[e];throw this.raise(this.state.start,Y.UnsupportedDeclareExportKind,e,t)}if(this.match(p._var)||this.match(p._function)||this.match(p._class)||this.isContextual("opaque"))return e.declaration=this.flowParseDeclare(this.startNode()),e.default=!1,this.finishNode(e,"DeclareExportDeclaration");if(this.match(p.star)||this.match(p.braceL)||this.isContextual("interface")||this.isContextual("type")||this.isContextual("opaque"))return"ExportNamedDeclaration"===(e=this.parseExport(e)).type&&(e.type="ExportDeclaration",e.default=!1,delete e.exportKind),e.type="Declare"+e.type,e;throw this.unexpected()}flowParseDeclareModuleExports(e){return this.next(),this.expectContextual("exports"),e.typeAnnotation=this.flowParseTypeAnnotation(),this.semicolon(),this.finishNode(e,"DeclareModuleExports")}flowParseDeclareTypeAlias(e){return this.next(),this.flowParseTypeAlias(e),e.type="DeclareTypeAlias",e}flowParseDeclareOpaqueType(e){return this.next(),this.flowParseOpaqueType(e,!0),e.type="DeclareOpaqueType",e}flowParseDeclareInterface(e){return this.next(),this.flowParseInterfaceish(e),this.finishNode(e,"DeclareInterface")}flowParseInterfaceish(e,t=!1){if(e.id=this.flowParseRestrictedIdentifier(!t,!0),this.scope.declareName(e.id.name,t?17:9,e.id.start),this.isRelational("<")?e.typeParameters=this.flowParseTypeParameterDeclaration():e.typeParameters=null,e.extends=[],e.implements=[],e.mixins=[],this.eat(p._extends))do{e.extends.push(this.flowParseInterfaceExtends())}while(!t&&this.eat(p.comma));if(this.isContextual("mixins")){this.next();do{e.mixins.push(this.flowParseInterfaceExtends())}while(this.eat(p.comma))}if(this.isContextual("implements")){this.next();do{e.implements.push(this.flowParseInterfaceExtends())}while(this.eat(p.comma))}e.body=this.flowParseObjectType({allowStatic:t,allowExact:!1,allowSpread:!1,allowProto:t,allowInexact:!1})}flowParseInterfaceExtends(){const e=this.startNode();return e.id=this.flowParseQualifiedTypeIdentifier(),this.isRelational("<")?e.typeParameters=this.flowParseTypeParameterInstantiation():e.typeParameters=null,this.finishNode(e,"InterfaceExtends")}flowParseInterface(e){return this.flowParseInterfaceish(e),this.finishNode(e,"InterfaceDeclaration")}checkNotUnderscore(e){"_"===e&&this.raise(this.state.start,Y.UnexpectedReservedUnderscore)}checkReservedType(e,t,r){J.has(e)&&this.raise(t,r?Y.AssignReservedType:Y.UnexpectedReservedType,e)}flowParseRestrictedIdentifier(e,t){return this.checkReservedType(this.state.value,this.state.start,t),this.parseIdentifier(e)}flowParseTypeAlias(e){return e.id=this.flowParseRestrictedIdentifier(!1,!0),this.scope.declareName(e.id.name,9,e.id.start),this.isRelational("<")?e.typeParameters=this.flowParseTypeParameterDeclaration():e.typeParameters=null,e.right=this.flowParseTypeInitialiser(p.eq),this.semicolon(),this.finishNode(e,"TypeAlias")}flowParseOpaqueType(e,t){return this.expectContextual("type"),e.id=this.flowParseRestrictedIdentifier(!0,!0),this.scope.declareName(e.id.name,9,e.id.start),this.isRelational("<")?e.typeParameters=this.flowParseTypeParameterDeclaration():e.typeParameters=null,e.supertype=null,this.match(p.colon)&&(e.supertype=this.flowParseTypeInitialiser(p.colon)),e.impltype=null,t||(e.impltype=this.flowParseTypeInitialiser(p.eq)),this.semicolon(),this.finishNode(e,"OpaqueType")}flowParseTypeParameter(e=!1){const t=this.state.start,r=this.startNode(),n=this.flowParseVariance(),s=this.flowParseTypeAnnotatableIdentifier();return r.name=s.name,r.variance=n,r.bound=s.typeAnnotation,this.match(p.eq)?(this.eat(p.eq),r.default=this.flowParseType()):e&&this.raise(t,Y.MissingTypeParamDefault),this.finishNode(r,"TypeParameter")}flowParseTypeParameterDeclaration(){const e=this.state.inType,t=this.startNode();t.params=[],this.state.inType=!0,this.isRelational("<")||this.match(p.jsxTagStart)?this.next():this.unexpected();let r=!1;do{const e=this.flowParseTypeParameter(r);t.params.push(e),e.default&&(r=!0),this.isRelational(">")||this.expect(p.comma)}while(!this.isRelational(">"));return this.expectRelational(">"),this.state.inType=e,this.finishNode(t,"TypeParameterDeclaration")}flowParseTypeParameterInstantiation(){const e=this.startNode(),t=this.state.inType;e.params=[],this.state.inType=!0,this.expectRelational("<");const r=this.state.noAnonFunctionType;for(this.state.noAnonFunctionType=!1;!this.isRelational(">");)e.params.push(this.flowParseType()),this.isRelational(">")||this.expect(p.comma);return this.state.noAnonFunctionType=r,this.expectRelational(">"),this.state.inType=t,this.finishNode(e,"TypeParameterInstantiation")}flowParseTypeParameterInstantiationCallOrNew(){const e=this.startNode(),t=this.state.inType;for(e.params=[],this.state.inType=!0,this.expectRelational("<");!this.isRelational(">");)e.params.push(this.flowParseTypeOrImplicitInstantiation()),this.isRelational(">")||this.expect(p.comma);return this.expectRelational(">"),this.state.inType=t,this.finishNode(e,"TypeParameterInstantiation")}flowParseInterfaceType(){const e=this.startNode();if(this.expectContextual("interface"),e.extends=[],this.eat(p._extends))do{e.extends.push(this.flowParseInterfaceExtends())}while(this.eat(p.comma));return e.body=this.flowParseObjectType({allowStatic:!1,allowExact:!1,allowSpread:!1,allowProto:!1,allowInexact:!1}),this.finishNode(e,"InterfaceTypeAnnotation")}flowParseObjectPropertyKey(){return this.match(p.num)||this.match(p.string)?this.parseExprAtom():this.parseIdentifier(!0)}flowParseObjectTypeIndexer(e,t,r){return e.static=t,this.lookahead().type===p.colon?(e.id=this.flowParseObjectPropertyKey(),e.key=this.flowParseTypeInitialiser()):(e.id=null,e.key=this.flowParseType()),this.expect(p.bracketR),e.value=this.flowParseTypeInitialiser(),e.variance=r,this.finishNode(e,"ObjectTypeIndexer")}flowParseObjectTypeInternalSlot(e,t){return e.static=t,e.id=this.flowParseObjectPropertyKey(),this.expect(p.bracketR),this.expect(p.bracketR),this.isRelational("<")||this.match(p.parenL)?(e.method=!0,e.optional=!1,e.value=this.flowParseObjectTypeMethodish(this.startNodeAt(e.start,e.loc.start))):(e.method=!1,this.eat(p.question)&&(e.optional=!0),e.value=this.flowParseTypeInitialiser()),this.finishNode(e,"ObjectTypeInternalSlot")}flowParseObjectTypeMethodish(e){for(e.params=[],e.rest=null,e.typeParameters=null,e.this=null,this.isRelational("<")&&(e.typeParameters=this.flowParseTypeParameterDeclaration()),this.expect(p.parenL),this.match(p._this)&&(e.this=this.flowParseFunctionTypeParam(!0),e.this.name=null,this.match(p.parenR)||this.expect(p.comma));!this.match(p.parenR)&&!this.match(p.ellipsis);)e.params.push(this.flowParseFunctionTypeParam(!1)),this.match(p.parenR)||this.expect(p.comma);return this.eat(p.ellipsis)&&(e.rest=this.flowParseFunctionTypeParam(!1)),this.expect(p.parenR),e.returnType=this.flowParseTypeInitialiser(),this.finishNode(e,"FunctionTypeAnnotation")}flowParseObjectTypeCallProperty(e,t){const r=this.startNode();return e.static=t,e.value=this.flowParseObjectTypeMethodish(r),this.finishNode(e,"ObjectTypeCallProperty")}flowParseObjectType({allowStatic:e,allowExact:t,allowSpread:r,allowProto:n,allowInexact:s}){const i=this.state.inType;this.state.inType=!0;const o=this.startNode();let a,l;o.callProperties=[],o.properties=[],o.indexers=[],o.internalSlots=[];let c=!1;for(t&&this.match(p.braceBarL)?(this.expect(p.braceBarL),a=p.braceBarR,l=!0):(this.expect(p.braceL),a=p.braceR,l=!1),o.exact=l;!this.match(a);){let t=!1,i=null,a=null;const u=this.startNode();if(n&&this.isContextual("proto")){const t=this.lookahead();t.type!==p.colon&&t.type!==p.question&&(this.next(),i=this.state.start,e=!1)}if(e&&this.isContextual("static")){const e=this.lookahead();e.type!==p.colon&&e.type!==p.question&&(this.next(),t=!0)}const f=this.flowParseVariance();if(this.eat(p.bracketL))null!=i&&this.unexpected(i),this.eat(p.bracketL)?(f&&this.unexpected(f.start),o.internalSlots.push(this.flowParseObjectTypeInternalSlot(u,t))):o.indexers.push(this.flowParseObjectTypeIndexer(u,t,f));else if(this.match(p.parenL)||this.isRelational("<"))null!=i&&this.unexpected(i),f&&this.unexpected(f.start),o.callProperties.push(this.flowParseObjectTypeCallProperty(u,t));else{let e="init";if(this.isContextual("get")||this.isContextual("set")){const t=this.lookahead();t.type!==p.name&&t.type!==p.string&&t.type!==p.num||(e=this.state.value,this.next())}const n=this.flowParseObjectTypeProperty(u,t,i,f,e,r,null!=s?s:!l);null===n?(c=!0,a=this.state.lastTokStart):o.properties.push(n)}this.flowObjectTypeSemicolon(),!a||this.match(p.braceR)||this.match(p.braceBarR)||this.raise(a,Y.UnexpectedExplicitInexactInObject)}this.expect(a),r&&(o.inexact=c);const u=this.finishNode(o,"ObjectTypeAnnotation");return this.state.inType=i,u}flowParseObjectTypeProperty(e,t,r,n,s,i,o){if(this.eat(p.ellipsis))return this.match(p.comma)||this.match(p.semi)||this.match(p.braceR)||this.match(p.braceBarR)?(i?o||this.raise(this.state.lastTokStart,Y.InexactInsideExact):this.raise(this.state.lastTokStart,Y.InexactInsideNonObject),n&&this.raise(n.start,Y.InexactVariance),null):(i||this.raise(this.state.lastTokStart,Y.UnexpectedSpreadType),null!=r&&this.unexpected(r),n&&this.raise(n.start,Y.SpreadVariance),e.argument=this.flowParseType(),this.finishNode(e,"ObjectTypeSpreadProperty"));{e.key=this.flowParseObjectPropertyKey(),e.static=t,e.proto=null!=r,e.kind=s;let o=!1;return this.isRelational("<")||this.match(p.parenL)?(e.method=!0,null!=r&&this.unexpected(r),n&&this.unexpected(n.start),e.value=this.flowParseObjectTypeMethodish(this.startNodeAt(e.start,e.loc.start)),"get"!==s&&"set"!==s||this.flowCheckGetterSetterParams(e),!i&&"constructor"===e.key.name&&e.value.this&&this.raise(e.value.this.start,Y.ThisParamBannedInConstructor)):("init"!==s&&this.unexpected(),e.method=!1,this.eat(p.question)&&(o=!0),e.value=this.flowParseTypeInitialiser(),e.variance=n),e.optional=o,this.finishNode(e,"ObjectTypeProperty")}}flowCheckGetterSetterParams(e){const t="get"===e.kind?0:1,r=e.start,n=e.value.params.length+(e.value.rest?1:0);e.value.this&&this.raise(e.value.this.start,"get"===e.kind?Y.GetterMayNotHaveThisParam:Y.SetterMayNotHaveThisParam),n!==t&&("get"===e.kind?this.raise(r,x.BadGetterArity):this.raise(r,x.BadSetterArity)),"set"===e.kind&&e.value.rest&&this.raise(r,x.BadSetterRestParameter)}flowObjectTypeSemicolon(){this.eat(p.semi)||this.eat(p.comma)||this.match(p.braceR)||this.match(p.braceBarR)||this.unexpected()}flowParseQualifiedTypeIdentifier(e,t,r){e=e||this.state.start,t=t||this.state.startLoc;let n=r||this.flowParseRestrictedIdentifier(!0);for(;this.eat(p.dot);){const r=this.startNodeAt(e,t);r.qualification=n,r.id=this.flowParseRestrictedIdentifier(!0),n=this.finishNode(r,"QualifiedTypeIdentifier")}return n}flowParseGenericType(e,t,r){const n=this.startNodeAt(e,t);return n.typeParameters=null,n.id=this.flowParseQualifiedTypeIdentifier(e,t,r),this.isRelational("<")&&(n.typeParameters=this.flowParseTypeParameterInstantiation()),this.finishNode(n,"GenericTypeAnnotation")}flowParseTypeofType(){const e=this.startNode();return this.expect(p._typeof),e.argument=this.flowParsePrimaryType(),this.finishNode(e,"TypeofTypeAnnotation")}flowParseTupleType(){const e=this.startNode();for(e.types=[],this.expect(p.bracketL);this.state.possuper.parseFunctionBody(e,!0,r))):super.parseFunctionBody(e,!1,r)}parseFunctionBodyAndFinish(e,t,r=!1){if(this.match(p.colon)){const t=this.startNode();[t.typeAnnotation,e.predicate]=this.flowParseTypeAndPredicateInitialiser(),e.returnType=t.typeAnnotation?this.finishNode(t,"TypeAnnotation"):null}super.parseFunctionBodyAndFinish(e,t,r)}parseStatement(e,t){if(this.state.strict&&this.match(p.name)&&"interface"===this.state.value){const e=this.lookahead();if(e.type===p.name||q(e.value)){const e=this.startNode();return this.next(),this.flowParseInterface(e)}}else if(this.shouldParseEnums()&&this.isContextual("enum")){const e=this.startNode();return this.next(),this.flowParseEnumDeclaration(e)}const r=super.parseStatement(e,t);return void 0!==this.flowPragma||this.isValidDirective(r)||(this.flowPragma=null),r}parseExpressionStatement(e,t){if("Identifier"===t.type)if("declare"===t.name){if(this.match(p._class)||this.match(p.name)||this.match(p._function)||this.match(p._var)||this.match(p._export))return this.flowParseDeclare(e)}else if(this.match(p.name)){if("interface"===t.name)return this.flowParseInterface(e);if("type"===t.name)return this.flowParseTypeAlias(e);if("opaque"===t.name)return this.flowParseOpaqueType(e,!1)}return super.parseExpressionStatement(e,t)}shouldParseExportDeclaration(){return this.isContextual("type")||this.isContextual("interface")||this.isContextual("opaque")||this.shouldParseEnums()&&this.isContextual("enum")||super.shouldParseExportDeclaration()}isExportDefaultSpecifier(){return(!this.match(p.name)||!("type"===this.state.value||"interface"===this.state.value||"opaque"===this.state.value||this.shouldParseEnums()&&"enum"===this.state.value))&&super.isExportDefaultSpecifier()}parseExportDefaultExpression(){if(this.shouldParseEnums()&&this.isContextual("enum")){const e=this.startNode();return this.next(),this.flowParseEnumDeclaration(e)}return super.parseExportDefaultExpression()}parseConditional(e,t,r,n){if(!this.match(p.question))return e;if(this.state.maybeInArrowParameters){const s=this.tryParse((()=>super.parseConditional(e,t,r)));return s.node?(s.error&&(this.state=s.failState),s.node):(s.error&&super.setOptionalParametersError(n,s.error),e)}this.expect(p.question);const s=this.state.clone(),i=this.state.noArrowAt,o=this.startNodeAt(t,r);let{consequent:a,failed:l}=this.tryParseConditionalConsequent(),[c,u]=this.getArrowLikeExpressions(a);if(l||u.length>0){const e=[...i];if(u.length>0){this.state=s,this.state.noArrowAt=e;for(let t=0;t1&&this.raise(s.start,Y.AmbiguousConditionalArrow),l&&1===c.length&&(this.state=s,this.state.noArrowAt=e.concat(c[0].start),({consequent:a,failed:l}=this.tryParseConditionalConsequent()))}return this.getArrowLikeExpressions(a,!0),this.state.noArrowAt=i,this.expect(p.colon),o.test=e,o.consequent=a,o.alternate=this.forwardNoArrowParamsConversionAt(o,(()=>this.parseMaybeAssign(void 0,void 0))),this.finishNode(o,"ConditionalExpression")}tryParseConditionalConsequent(){this.state.noArrowParamsConversionAt.push(this.state.start);const e=this.parseMaybeAssignAllowIn(),t=!this.match(p.colon);return this.state.noArrowParamsConversionAt.pop(),{consequent:e,failed:t}}getArrowLikeExpressions(e,t){const r=[e],n=[];for(;0!==r.length;){const e=r.pop();"ArrowFunctionExpression"===e.type?(e.typeParameters||!e.returnType?this.finishArrowValidation(e):n.push(e),r.push(e.body)):"ConditionalExpression"===e.type&&(r.push(e.consequent),r.push(e.alternate))}return t?(n.forEach((e=>this.finishArrowValidation(e))),[n,[]]):function(e,t){const r=[],n=[];for(let s=0;se.params.every((e=>this.isAssignable(e,!0)))))}finishArrowValidation(e){var t;this.toAssignableList(e.params,null==(t=e.extra)?void 0:t.trailingComma,!1),this.scope.enter(6),super.checkParams(e,!1,!0),this.scope.exit()}forwardNoArrowParamsConversionAt(e,t){let r;return-1!==this.state.noArrowParamsConversionAt.indexOf(e.start)?(this.state.noArrowParamsConversionAt.push(this.state.start),r=t(),this.state.noArrowParamsConversionAt.pop()):r=t(),r}parseParenItem(e,t,r){if(e=super.parseParenItem(e,t,r),this.eat(p.question)&&(e.optional=!0,this.resetEndLocation(e)),this.match(p.colon)){const n=this.startNodeAt(t,r);return n.expression=e,n.typeAnnotation=this.flowParseTypeAnnotation(),this.finishNode(n,"TypeCastExpression")}return e}assertModuleNodeAllowed(e){"ImportDeclaration"===e.type&&("type"===e.importKind||"typeof"===e.importKind)||"ExportNamedDeclaration"===e.type&&"type"===e.exportKind||"ExportAllDeclaration"===e.type&&"type"===e.exportKind||super.assertModuleNodeAllowed(e)}parseExport(e){const t=super.parseExport(e);return"ExportNamedDeclaration"!==t.type&&"ExportAllDeclaration"!==t.type||(t.exportKind=t.exportKind||"value"),t}parseExportDeclaration(e){if(this.isContextual("type")){e.exportKind="type";const t=this.startNode();return this.next(),this.match(p.braceL)?(e.specifiers=this.parseExportSpecifiers(),this.parseExportFrom(e),null):this.flowParseTypeAlias(t)}if(this.isContextual("opaque")){e.exportKind="type";const t=this.startNode();return this.next(),this.flowParseOpaqueType(t,!1)}if(this.isContextual("interface")){e.exportKind="type";const t=this.startNode();return this.next(),this.flowParseInterface(t)}if(this.shouldParseEnums()&&this.isContextual("enum")){e.exportKind="value";const t=this.startNode();return this.next(),this.flowParseEnumDeclaration(t)}return super.parseExportDeclaration(e)}eatExportStar(e){return!!super.eatExportStar(...arguments)||!(!this.isContextual("type")||this.lookahead().type!==p.star)&&(e.exportKind="type",this.next(),this.next(),!0)}maybeParseExportNamespaceSpecifier(e){const t=this.state.start,r=super.maybeParseExportNamespaceSpecifier(e);return r&&"type"===e.exportKind&&this.unexpected(t),r}parseClassId(e,t,r){super.parseClassId(e,t,r),this.isRelational("<")&&(e.typeParameters=this.flowParseTypeParameterDeclaration())}parseClassMember(e,t,r){const n=this.state.start;if(this.isContextual("declare")){if(this.parseClassMemberFromModifier(e,t))return;t.declare=!0}super.parseClassMember(e,t,r),t.declare&&("ClassProperty"!==t.type&&"ClassPrivateProperty"!==t.type&&"PropertyDefinition"!==t.type?this.raise(n,Y.DeclareClassElement):t.value&&this.raise(t.value.start,Y.DeclareClassFieldInitializer))}isIterator(e){return"iterator"===e||"asyncIterator"===e}readIterator(){const e=super.readWord1(),t="@@"+e;this.isIterator(e)&&this.state.inType||this.raise(this.state.pos,x.InvalidIdentifier,t),this.finishToken(p.name,t)}getTokenFromCode(e){const t=this.input.charCodeAt(this.state.pos+1);return 123===e&&124===t?this.finishOp(p.braceBarL,2):!this.state.inType||62!==e&&60!==e?this.state.inType&&63===e?46===t?this.finishOp(p.questionDot,2):this.finishOp(p.question,1):function(e,t){return 64===e&&64===t}(e,t)?(this.state.pos+=2,this.readIterator()):super.getTokenFromCode(e):this.finishOp(p.relational,1)}isAssignable(e,t){switch(e.type){case"Identifier":case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":return!0;case"ObjectExpression":{const t=e.properties.length-1;return e.properties.every(((e,r)=>"ObjectMethod"!==e.type&&(r===t||"SpreadElement"===e.type)&&this.isAssignable(e)))}case"ObjectProperty":return this.isAssignable(e.value);case"SpreadElement":return this.isAssignable(e.argument);case"ArrayExpression":return e.elements.every((e=>this.isAssignable(e)));case"AssignmentExpression":return"="===e.operator;case"ParenthesizedExpression":case"TypeCastExpression":return this.isAssignable(e.expression);case"MemberExpression":case"OptionalMemberExpression":return!t;default:return!1}}toAssignable(e,t=!1){return"TypeCastExpression"===e.type?super.toAssignable(this.typeCastToParameter(e),t):super.toAssignable(e,t)}toAssignableList(e,t,r){for(let t=0;t1)&&t||this.raise(s.typeAnnotation.start,Y.TypeCastInPattern)}return e}parseArrayLike(e,t,r,n){const s=super.parseArrayLike(e,t,r,n);return t&&!this.state.maybeInArrowParameters&&this.toReferencedList(s.elements),s}checkLVal(e,...t){if("TypeCastExpression"!==e.type)return super.checkLVal(e,...t)}parseClassProperty(e){return this.match(p.colon)&&(e.typeAnnotation=this.flowParseTypeAnnotation()),super.parseClassProperty(e)}parseClassPrivateProperty(e){return this.match(p.colon)&&(e.typeAnnotation=this.flowParseTypeAnnotation()),super.parseClassPrivateProperty(e)}isClassMethod(){return this.isRelational("<")||super.isClassMethod()}isClassProperty(){return this.match(p.colon)||super.isClassProperty()}isNonstaticConstructor(e){return!this.match(p.colon)&&super.isNonstaticConstructor(e)}pushClassMethod(e,t,r,n,s,i){if(t.variance&&this.unexpected(t.variance.start),delete t.variance,this.isRelational("<")&&(t.typeParameters=this.flowParseTypeParameterDeclaration()),super.pushClassMethod(e,t,r,n,s,i),t.params&&s){const e=t.params;e.length>0&&this.isThisParam(e[0])&&this.raise(t.start,Y.ThisParamBannedInConstructor)}else if("MethodDefinition"===t.type&&s&&t.value.params){const e=t.value.params;e.length>0&&this.isThisParam(e[0])&&this.raise(t.start,Y.ThisParamBannedInConstructor)}}pushClassPrivateMethod(e,t,r,n){t.variance&&this.unexpected(t.variance.start),delete t.variance,this.isRelational("<")&&(t.typeParameters=this.flowParseTypeParameterDeclaration()),super.pushClassPrivateMethod(e,t,r,n)}parseClassSuper(e){if(super.parseClassSuper(e),e.superClass&&this.isRelational("<")&&(e.superTypeParameters=this.flowParseTypeParameterInstantiation()),this.isContextual("implements")){this.next();const t=e.implements=[];do{const e=this.startNode();e.id=this.flowParseRestrictedIdentifier(!0),this.isRelational("<")?e.typeParameters=this.flowParseTypeParameterInstantiation():e.typeParameters=null,t.push(this.finishNode(e,"ClassImplements"))}while(this.eat(p.comma))}}checkGetterSetterParams(e){super.checkGetterSetterParams(e);const t=this.getObjectOrClassMethodParams(e);if(t.length>0){const r=t[0];this.isThisParam(r)&&"get"===e.kind?this.raise(r.start,Y.GetterMayNotHaveThisParam):this.isThisParam(r)&&this.raise(r.start,Y.SetterMayNotHaveThisParam)}}parsePropertyName(e,t){const r=this.flowParseVariance(),n=super.parsePropertyName(e,t);return e.variance=r,n}parseObjPropValue(e,t,r,n,s,i,o,a){let l;e.variance&&this.unexpected(e.variance.start),delete e.variance,this.isRelational("<")&&!o&&(l=this.flowParseTypeParameterDeclaration(),this.match(p.parenL)||this.unexpected()),super.parseObjPropValue(e,t,r,n,s,i,o,a),l&&((e.value||e).typeParameters=l)}parseAssignableListItemTypes(e){return this.eat(p.question)&&("Identifier"!==e.type&&this.raise(e.start,Y.OptionalBindingPattern),this.isThisParam(e)&&this.raise(e.start,Y.ThisParamMayNotBeOptional),e.optional=!0),this.match(p.colon)?e.typeAnnotation=this.flowParseTypeAnnotation():this.isThisParam(e)&&this.raise(e.start,Y.ThisParamAnnotationRequired),this.match(p.eq)&&this.isThisParam(e)&&this.raise(e.start,Y.ThisParamNoDefault),this.resetEndLocation(e),e}parseMaybeDefault(e,t,r){const n=super.parseMaybeDefault(e,t,r);return"AssignmentPattern"===n.type&&n.typeAnnotation&&n.right.startsuper.parseMaybeAssign(e,t)),s),!n.error)return n.node;const{context:r}=this.state,i=r[r.length-1];i===P.j_oTag?r.length-=2:i===P.j_expr&&(r.length-=1)}if(null!=(r=n)&&r.error||this.isRelational("<")){var i,o;let r;s=s||this.state.clone();const a=this.tryParse((n=>{var s;r=this.flowParseTypeParameterDeclaration();const i=this.forwardNoArrowParamsConversionAt(r,(()=>{const n=super.parseMaybeAssign(e,t);return this.resetStartLocationFromNode(n,r),n}));"ArrowFunctionExpression"!==i.type&&null!=(s=i.extra)&&s.parenthesized&&n();const o=this.maybeUnwrapTypeCastExpression(i);return o.typeParameters=r,this.resetStartLocationFromNode(o,r),i}),s);let l=null;if(a.node&&"ArrowFunctionExpression"===this.maybeUnwrapTypeCastExpression(a.node).type){if(!a.error&&!a.aborted)return a.node.async&&this.raise(r.start,Y.UnexpectedTypeParameterBeforeAsyncArrowFunction),a.node;l=a.node}if(null!=(i=n)&&i.node)return this.state=n.failState,n.node;if(l)return this.state=a.failState,l;if(null!=(o=n)&&o.thrown)throw n.error;if(a.thrown)throw a.error;throw this.raise(r.start,Y.UnexpectedTokenAfterTypeParameter)}return super.parseMaybeAssign(e,t)}parseArrow(e){if(this.match(p.colon)){const t=this.tryParse((()=>{const t=this.state.noAnonFunctionType;this.state.noAnonFunctionType=!0;const r=this.startNode();return[r.typeAnnotation,e.predicate]=this.flowParseTypeAndPredicateInitialiser(),this.state.noAnonFunctionType=t,this.canInsertSemicolon()&&this.unexpected(),this.match(p.arrow)||this.unexpected(),r}));if(t.thrown)return null;t.error&&(this.state=t.failState),e.returnType=t.node.typeAnnotation?this.finishNode(t.node,"TypeAnnotation"):null}return super.parseArrow(e)}shouldParseArrow(){return this.match(p.colon)||super.shouldParseArrow()}setArrowFunctionParameters(e,t){-1!==this.state.noArrowParamsConversionAt.indexOf(e.start)?e.params=t:super.setArrowFunctionParameters(e,t)}checkParams(e,t,r){if(!r||-1===this.state.noArrowParamsConversionAt.indexOf(e.start)){for(let t=0;t0&&this.raise(e.params[t].start,Y.ThisParamMustBeFirst);return super.checkParams(...arguments)}}parseParenAndDistinguishExpression(e){return super.parseParenAndDistinguishExpression(e&&-1===this.state.noArrowAt.indexOf(this.state.start))}parseSubscripts(e,t,r,n){if("Identifier"===e.type&&"async"===e.name&&-1!==this.state.noArrowAt.indexOf(t)){this.next();const n=this.startNodeAt(t,r);n.callee=e,n.arguments=this.parseCallExpressionArguments(p.parenR,!1),e=this.finishNode(n,"CallExpression")}else if("Identifier"===e.type&&"async"===e.name&&this.isRelational("<")){const s=this.state.clone(),i=this.tryParse((e=>this.parseAsyncArrowWithTypeParameters(t,r)||e()),s);if(!i.error&&!i.aborted)return i.node;const o=this.tryParse((()=>super.parseSubscripts(e,t,r,n)),s);if(o.node&&!o.error)return o.node;if(i.node)return this.state=i.failState,i.node;if(o.node)return this.state=o.failState,o.node;throw i.error||o.error}return super.parseSubscripts(e,t,r,n)}parseSubscript(e,t,r,n,s){if(this.match(p.questionDot)&&this.isLookaheadToken_lt()){if(s.optionalChainMember=!0,n)return s.stop=!0,e;this.next();const i=this.startNodeAt(t,r);return i.callee=e,i.typeArguments=this.flowParseTypeParameterInstantiation(),this.expect(p.parenL),i.arguments=this.parseCallExpressionArguments(p.parenR,!1),i.optional=!0,this.finishCallExpression(i,!0)}if(!n&&this.shouldParseTypes()&&this.isRelational("<")){const n=this.startNodeAt(t,r);n.callee=e;const i=this.tryParse((()=>(n.typeArguments=this.flowParseTypeParameterInstantiationCallOrNew(),this.expect(p.parenL),n.arguments=this.parseCallExpressionArguments(p.parenR,!1),s.optionalChainMember&&(n.optional=!1),this.finishCallExpression(n,s.optionalChainMember))));if(i.node)return i.error&&(this.state=i.failState),i.node}return super.parseSubscript(e,t,r,n,s)}parseNewArguments(e){let t=null;this.shouldParseTypes()&&this.isRelational("<")&&(t=this.tryParse((()=>this.flowParseTypeParameterInstantiationCallOrNew())).node),e.typeArguments=t,super.parseNewArguments(e)}parseAsyncArrowWithTypeParameters(e,t){const r=this.startNodeAt(e,t);if(this.parseFunctionParams(r),this.parseArrow(r))return this.parseArrowExpression(r,void 0,!0)}readToken_mult_modulo(e){const t=this.input.charCodeAt(this.state.pos+1);if(42===e&&47===t&&this.state.hasFlowComment)return this.state.hasFlowComment=!1,this.state.pos+=2,void this.nextToken();super.readToken_mult_modulo(e)}readToken_pipe_amp(e){const t=this.input.charCodeAt(this.state.pos+1);124!==e||125!==t?super.readToken_pipe_amp(e):this.finishOp(p.braceBarR,2)}parseTopLevel(e,t){const r=super.parseTopLevel(e,t);return this.state.hasFlowComment&&this.raise(this.state.pos,Y.UnterminatedFlowComment),r}skipBlockComment(){if(this.hasPlugin("flowComments")&&this.skipFlowComment())return this.state.hasFlowComment&&this.unexpected(null,Y.NestedFlowComment),this.hasFlowCommentCompletion(),this.state.pos+=this.skipFlowComment(),void(this.state.hasFlowComment=!0);if(this.state.hasFlowComment){const e=this.input.indexOf("*-/",this.state.pos+=2);if(-1===e)throw this.raise(this.state.pos-2,x.UnterminatedComment);this.state.pos=e+3}else super.skipBlockComment()}skipFlowComment(){const{pos:e}=this.state;let t=2;for(;[32,9].includes(this.input.charCodeAt(e+t));)t++;const r=this.input.charCodeAt(t+e),n=this.input.charCodeAt(t+e+1);return 58===r&&58===n?t+2:"flow-include"===this.input.slice(t+e,t+e+12)?t+12:58===r&&58!==n&&t}hasFlowCommentCompletion(){if(-1===this.input.indexOf("*/",this.state.pos))throw this.raise(this.state.pos,x.UnterminatedComment)}flowEnumErrorBooleanMemberNotInitialized(e,{enumName:t,memberName:r}){this.raise(e,Y.EnumBooleanMemberNotInitialized,r,t)}flowEnumErrorInvalidMemberName(e,{enumName:t,memberName:r}){const n=r[0].toUpperCase()+r.slice(1);this.raise(e,Y.EnumInvalidMemberName,r,n,t)}flowEnumErrorDuplicateMemberName(e,{enumName:t,memberName:r}){this.raise(e,Y.EnumDuplicateMemberName,r,t)}flowEnumErrorInconsistentMemberValues(e,{enumName:t}){this.raise(e,Y.EnumInconsistentMemberValues,t)}flowEnumErrorInvalidExplicitType(e,{enumName:t,suppliedType:r}){return this.raise(e,null===r?Y.EnumInvalidExplicitTypeUnknownSupplied:Y.EnumInvalidExplicitType,t,r)}flowEnumErrorInvalidMemberInitializer(e,{enumName:t,explicitType:r,memberName:n}){let s=null;switch(r){case"boolean":case"number":case"string":s=Y.EnumInvalidMemberInitializerPrimaryType;break;case"symbol":s=Y.EnumInvalidMemberInitializerSymbolType;break;default:s=Y.EnumInvalidMemberInitializerUnknownType}return this.raise(e,s,t,n,r)}flowEnumErrorNumberMemberNotInitialized(e,{enumName:t,memberName:r}){this.raise(e,Y.EnumNumberMemberNotInitialized,t,r)}flowEnumErrorStringMemberInconsistentlyInitailized(e,{enumName:t}){this.raise(e,Y.EnumStringMemberInconsistentlyInitailized,t)}flowEnumMemberInit(){const e=this.state.start,t=()=>this.match(p.comma)||this.match(p.braceR);switch(this.state.type){case p.num:{const r=this.parseNumericLiteral(this.state.value);return t()?{type:"number",pos:r.start,value:r}:{type:"invalid",pos:e}}case p.string:{const r=this.parseStringLiteral(this.state.value);return t()?{type:"string",pos:r.start,value:r}:{type:"invalid",pos:e}}case p._true:case p._false:{const r=this.parseBooleanLiteral(this.match(p._true));return t()?{type:"boolean",pos:r.start,value:r}:{type:"invalid",pos:e}}default:return{type:"invalid",pos:e}}}flowEnumMemberRaw(){const e=this.state.start;return{id:this.parseIdentifier(!0),init:this.eat(p.eq)?this.flowEnumMemberInit():{type:"none",pos:e}}}flowEnumCheckExplicitTypeMismatch(e,t,r){const{explicitType:n}=t;null!==n&&n!==r&&this.flowEnumErrorInvalidMemberInitializer(e,t)}flowEnumMembers({enumName:e,explicitType:t}){const r=new Set,n={booleanMembers:[],numberMembers:[],stringMembers:[],defaultedMembers:[]};let s=!1;for(;!this.match(p.braceR);){if(this.eat(p.ellipsis)){s=!0;break}const i=this.startNode(),{id:o,init:a}=this.flowEnumMemberRaw(),l=o.name;if(""===l)continue;/^[a-z]/.test(l)&&this.flowEnumErrorInvalidMemberName(o.start,{enumName:e,memberName:l}),r.has(l)&&this.flowEnumErrorDuplicateMemberName(o.start,{enumName:e,memberName:l}),r.add(l);const c={enumName:e,explicitType:t,memberName:l};switch(i.id=o,a.type){case"boolean":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"boolean"),i.init=a.value,n.booleanMembers.push(this.finishNode(i,"EnumBooleanMember"));break;case"number":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"number"),i.init=a.value,n.numberMembers.push(this.finishNode(i,"EnumNumberMember"));break;case"string":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"string"),i.init=a.value,n.stringMembers.push(this.finishNode(i,"EnumStringMember"));break;case"invalid":throw this.flowEnumErrorInvalidMemberInitializer(a.pos,c);case"none":switch(t){case"boolean":this.flowEnumErrorBooleanMemberNotInitialized(a.pos,c);break;case"number":this.flowEnumErrorNumberMemberNotInitialized(a.pos,c);break;default:n.defaultedMembers.push(this.finishNode(i,"EnumDefaultedMember"))}}this.match(p.braceR)||this.expect(p.comma)}return{members:n,hasUnknownMembers:s}}flowEnumStringMembers(e,t,{enumName:r}){if(0===e.length)return t;if(0===t.length)return e;if(t.length>e.length){for(const t of e)this.flowEnumErrorStringMemberInconsistentlyInitailized(t.start,{enumName:r});return t}for(const e of t)this.flowEnumErrorStringMemberInconsistentlyInitailized(e.start,{enumName:r});return e}flowEnumParseExplicitType({enumName:e}){if(this.eatContextual("of")){if(!this.match(p.name))throw this.flowEnumErrorInvalidExplicitType(this.state.start,{enumName:e,suppliedType:null});const{value:t}=this.state;return this.next(),"boolean"!==t&&"number"!==t&&"string"!==t&&"symbol"!==t&&this.flowEnumErrorInvalidExplicitType(this.state.start,{enumName:e,suppliedType:t}),t}return null}flowEnumBody(e,{enumName:t,nameLoc:r}){const n=this.flowEnumParseExplicitType({enumName:t});this.expect(p.braceL);const{members:s,hasUnknownMembers:i}=this.flowEnumMembers({enumName:t,explicitType:n});switch(e.hasUnknownMembers=i,n){case"boolean":return e.explicitType=!0,e.members=s.booleanMembers,this.expect(p.braceR),this.finishNode(e,"EnumBooleanBody");case"number":return e.explicitType=!0,e.members=s.numberMembers,this.expect(p.braceR),this.finishNode(e,"EnumNumberBody");case"string":return e.explicitType=!0,e.members=this.flowEnumStringMembers(s.stringMembers,s.defaultedMembers,{enumName:t}),this.expect(p.braceR),this.finishNode(e,"EnumStringBody");case"symbol":return e.members=s.defaultedMembers,this.expect(p.braceR),this.finishNode(e,"EnumSymbolBody");default:{const n=()=>(e.members=[],this.expect(p.braceR),this.finishNode(e,"EnumStringBody"));e.explicitType=!1;const i=s.booleanMembers.length,o=s.numberMembers.length,a=s.stringMembers.length,l=s.defaultedMembers.length;if(i||o||a||l){if(i||o){if(!o&&!a&&i>=l){for(const e of s.defaultedMembers)this.flowEnumErrorBooleanMemberNotInitialized(e.start,{enumName:t,memberName:e.id.name});return e.members=s.booleanMembers,this.expect(p.braceR),this.finishNode(e,"EnumBooleanBody")}if(!i&&!a&&o>=l){for(const e of s.defaultedMembers)this.flowEnumErrorNumberMemberNotInitialized(e.start,{enumName:t,memberName:e.id.name});return e.members=s.numberMembers,this.expect(p.braceR),this.finishNode(e,"EnumNumberBody")}return this.flowEnumErrorInconsistentMemberValues(r,{enumName:t}),n()}return e.members=this.flowEnumStringMembers(s.stringMembers,s.defaultedMembers,{enumName:t}),this.expect(p.braceR),this.finishNode(e,"EnumStringBody")}return n()}}}flowParseEnumDeclaration(e){const t=this.parseIdentifier();return e.id=t,e.body=this.flowEnumBody(this.startNode(),{enumName:t.name,nameLoc:t.start}),this.finishNode(e,"EnumDeclaration")}isLookaheadToken_lt(){const e=this.nextTokenStart();if(60===this.input.charCodeAt(e)){const t=this.input.charCodeAt(e+1);return 60!==t&&61!==t}return!1}maybeUnwrapTypeCastExpression(e){return"TypeCastExpression"===e.type?e.expression:e}},typescript:e=>class extends e{getScopeHandler(){return le}tsIsIdentifier(){return this.match(p.name)}tsTokenCanFollowModifier(){return(this.match(p.bracketL)||this.match(p.braceL)||this.match(p.star)||this.match(p.ellipsis)||this.match(p.privateName)||this.isLiteralPropertyName())&&!this.hasPrecedingLineBreak()}tsNextTokenCanFollowModifier(){return this.next(),this.tsTokenCanFollowModifier()}tsParseModifier(e){if(!this.match(p.name))return;const t=this.state.value;return-1!==e.indexOf(t)&&this.tsTryParse(this.tsNextTokenCanFollowModifier.bind(this))?t:void 0}tsParseModifiers(e,t,r,n){const s=(t,r,n,s)=>{r===n&&e[s]&&this.raise(t,de.InvalidModifiersOrder,n,s)},i=(t,r,n,s)=>{(e[n]&&r===s||e[s]&&r===n)&&this.raise(t,de.IncompatibleModifiers,n,s)};for(;;){const o=this.state.start,a=this.tsParseModifier(t.concat(null!=r?r:[]));if(!a)break;he(a)?e.accessibility?this.raise(o,de.DuplicateAccessibilityModifier):(s(o,a,a,"override"),s(o,a,a,"static"),s(o,a,a,"readonly"),e.accessibility=a):(Object.hasOwnProperty.call(e,a)?this.raise(o,de.DuplicateModifier,a):(s(o,a,"static","readonly"),s(o,a,"static","override"),s(o,a,"override","readonly"),s(o,a,"abstract","override"),i(o,a,"declare","override"),i(o,a,"static","abstract")),e[a]=!0),null!=r&&r.includes(a)&&this.raise(o,n,a)}}tsIsListTerminator(e){switch(e){case"EnumMembers":case"TypeMembers":return this.match(p.braceR);case"HeritageClauseElement":return this.match(p.braceL);case"TupleElementTypes":return this.match(p.bracketR);case"TypeParametersOrArguments":return this.isRelational(">")}throw new Error("Unreachable")}tsParseList(e,t){const r=[];for(;!this.tsIsListTerminator(e);)r.push(t());return r}tsParseDelimitedList(e,t){return pe(this.tsParseDelimitedListWorker(e,t,!0))}tsParseDelimitedListWorker(e,t,r){const n=[];for(;!this.tsIsListTerminator(e);){const s=t();if(null==s)return;if(n.push(s),!this.eat(p.comma)){if(this.tsIsListTerminator(e))break;return void(r&&this.expect(p.comma))}}return n}tsParseBracketedList(e,t,r,n){n||(r?this.expect(p.bracketL):this.expectRelational("<"));const s=this.tsParseDelimitedList(e,t);return r?this.expect(p.bracketR):this.expectRelational(">"),s}tsParseImportType(){const e=this.startNode();return this.expect(p._import),this.expect(p.parenL),this.match(p.string)||this.raise(this.state.start,de.UnsupportedImportTypeArgument),e.argument=this.parseExprAtom(),this.expect(p.parenR),this.eat(p.dot)&&(e.qualifier=this.tsParseEntityName(!0)),this.isRelational("<")&&(e.typeParameters=this.tsParseTypeArguments()),this.finishNode(e,"TSImportType")}tsParseEntityName(e){let t=this.parseIdentifier();for(;this.eat(p.dot);){const r=this.startNodeAtNode(t);r.left=t,r.right=this.parseIdentifier(e),t=this.finishNode(r,"TSQualifiedName")}return t}tsParseTypeReference(){const e=this.startNode();return e.typeName=this.tsParseEntityName(!1),!this.hasPrecedingLineBreak()&&this.isRelational("<")&&(e.typeParameters=this.tsParseTypeArguments()),this.finishNode(e,"TSTypeReference")}tsParseThisTypePredicate(e){this.next();const t=this.startNodeAtNode(e);return t.parameterName=e,t.typeAnnotation=this.tsParseTypeAnnotation(!1),t.asserts=!1,this.finishNode(t,"TSTypePredicate")}tsParseThisTypeNode(){const e=this.startNode();return this.next(),this.finishNode(e,"TSThisType")}tsParseTypeQuery(){const e=this.startNode();return this.expect(p._typeof),this.match(p._import)?e.exprName=this.tsParseImportType():e.exprName=this.tsParseEntityName(!0),this.finishNode(e,"TSTypeQuery")}tsParseTypeParameter(){const e=this.startNode();return e.name=this.parseIdentifierName(e.start),e.constraint=this.tsEatThenParseType(p._extends),e.default=this.tsEatThenParseType(p.eq),this.finishNode(e,"TSTypeParameter")}tsTryParseTypeParameters(){if(this.isRelational("<"))return this.tsParseTypeParameters()}tsParseTypeParameters(){const e=this.startNode();return this.isRelational("<")||this.match(p.jsxTagStart)?this.next():this.unexpected(),e.params=this.tsParseBracketedList("TypeParametersOrArguments",this.tsParseTypeParameter.bind(this),!1,!0),0===e.params.length&&this.raise(e.start,de.EmptyTypeParameters),this.finishNode(e,"TSTypeParameterDeclaration")}tsTryNextParseConstantContext(){return this.lookahead().type===p._const?(this.next(),this.tsParseTypeReference()):null}tsFillSignature(e,t){const r=e===p.arrow;t.typeParameters=this.tsTryParseTypeParameters(),this.expect(p.parenL),t.parameters=this.tsParseBindingListForSignature(),(r||this.match(e))&&(t.typeAnnotation=this.tsParseTypeOrTypePredicateAnnotation(e))}tsParseBindingListForSignature(){return this.parseBindingList(p.parenR,41).map((e=>("Identifier"!==e.type&&"RestElement"!==e.type&&"ObjectPattern"!==e.type&&"ArrayPattern"!==e.type&&this.raise(e.start,de.UnsupportedSignatureParameterKind,e.type),e)))}tsParseTypeMemberSemicolon(){this.eat(p.comma)||this.isLineTerminator()||this.expect(p.semi)}tsParseSignatureMember(e,t){return this.tsFillSignature(p.colon,t),this.tsParseTypeMemberSemicolon(),this.finishNode(t,e)}tsIsUnambiguouslyIndexSignature(){return this.next(),this.eat(p.name)&&this.match(p.colon)}tsTryParseIndexSignature(e){if(!this.match(p.bracketL)||!this.tsLookAhead(this.tsIsUnambiguouslyIndexSignature.bind(this)))return;this.expect(p.bracketL);const t=this.parseIdentifier();t.typeAnnotation=this.tsParseTypeAnnotation(),this.resetEndLocation(t),this.expect(p.bracketR),e.parameters=[t];const r=this.tsTryParseTypeAnnotation();return r&&(e.typeAnnotation=r),this.tsParseTypeMemberSemicolon(),this.finishNode(e,"TSIndexSignature")}tsParsePropertyOrMethodSignature(e,t){this.eat(p.question)&&(e.optional=!0);const r=e;if(this.match(p.parenL)||this.isRelational("<")){t&&this.raise(e.start,de.ReadonlyForMethodSignature);const n=r;if(n.kind&&this.isRelational("<")&&this.raise(this.state.pos,de.AccesorCannotHaveTypeParameters),this.tsFillSignature(p.colon,n),this.tsParseTypeMemberSemicolon(),"get"===n.kind)n.parameters.length>0&&(this.raise(this.state.pos,x.BadGetterArity),this.isThisParam(n.parameters[0])&&this.raise(this.state.pos,de.AccesorCannotDeclareThisParameter));else if("set"===n.kind){if(1!==n.parameters.length)this.raise(this.state.pos,x.BadSetterArity);else{const e=n.parameters[0];this.isThisParam(e)&&this.raise(this.state.pos,de.AccesorCannotDeclareThisParameter),"Identifier"===e.type&&e.optional&&this.raise(this.state.pos,de.SetAccesorCannotHaveOptionalParameter),"RestElement"===e.type&&this.raise(this.state.pos,de.SetAccesorCannotHaveRestParameter)}n.typeAnnotation&&this.raise(n.typeAnnotation.start,de.SetAccesorCannotHaveReturnType)}else n.kind="method";return this.finishNode(n,"TSMethodSignature")}{const e=r;t&&(e.readonly=!0);const n=this.tsTryParseTypeAnnotation();return n&&(e.typeAnnotation=n),this.tsParseTypeMemberSemicolon(),this.finishNode(e,"TSPropertySignature")}}tsParseTypeMember(){const e=this.startNode();if(this.match(p.parenL)||this.isRelational("<"))return this.tsParseSignatureMember("TSCallSignatureDeclaration",e);if(this.match(p._new)){const t=this.startNode();return this.next(),this.match(p.parenL)||this.isRelational("<")?this.tsParseSignatureMember("TSConstructSignatureDeclaration",e):(e.key=this.createIdentifier(t,"new"),this.tsParsePropertyOrMethodSignature(e,!1))}this.tsParseModifiers(e,["readonly"],["declare","abstract","private","protected","public","static","override"],de.InvalidModifierOnTypeMember);return this.tsTryParseIndexSignature(e)||(this.parsePropertyName(e,!1),e.computed||"Identifier"!==e.key.type||"get"!==e.key.name&&"set"!==e.key.name||!this.tsTokenCanFollowModifier()||(e.kind=e.key.name,this.parsePropertyName(e,!1)),this.tsParsePropertyOrMethodSignature(e,!!e.readonly))}tsParseTypeLiteral(){const e=this.startNode();return e.members=this.tsParseObjectTypeMembers(),this.finishNode(e,"TSTypeLiteral")}tsParseObjectTypeMembers(){this.expect(p.braceL);const e=this.tsParseList("TypeMembers",this.tsParseTypeMember.bind(this));return this.expect(p.braceR),e}tsIsStartOfMappedType(){return this.next(),this.eat(p.plusMin)?this.isContextual("readonly"):(this.isContextual("readonly")&&this.next(),!!this.match(p.bracketL)&&(this.next(),!!this.tsIsIdentifier()&&(this.next(),this.match(p._in))))}tsParseMappedTypeParameter(){const e=this.startNode();return e.name=this.parseIdentifierName(e.start),e.constraint=this.tsExpectThenParseType(p._in),this.finishNode(e,"TSTypeParameter")}tsParseMappedType(){const e=this.startNode();return this.expect(p.braceL),this.match(p.plusMin)?(e.readonly=this.state.value,this.next(),this.expectContextual("readonly")):this.eatContextual("readonly")&&(e.readonly=!0),this.expect(p.bracketL),e.typeParameter=this.tsParseMappedTypeParameter(),e.nameType=this.eatContextual("as")?this.tsParseType():null,this.expect(p.bracketR),this.match(p.plusMin)?(e.optional=this.state.value,this.next(),this.expect(p.question)):this.eat(p.question)&&(e.optional=!0),e.typeAnnotation=this.tsTryParseType(),this.semicolon(),this.expect(p.braceR),this.finishNode(e,"TSMappedType")}tsParseTupleType(){const e=this.startNode();e.elementTypes=this.tsParseBracketedList("TupleElementTypes",this.tsParseTupleElementType.bind(this),!0,!1);let t=!1,r=null;return e.elementTypes.forEach((e=>{var n;let{type:s}=e;!t||"TSRestType"===s||"TSOptionalType"===s||"TSNamedTupleMember"===s&&e.optional||this.raise(e.start,de.OptionalTypeBeforeRequired),t=t||"TSNamedTupleMember"===s&&e.optional||"TSOptionalType"===s,"TSRestType"===s&&(s=(e=e.typeAnnotation).type);const i="TSNamedTupleMember"===s;r=null!=(n=r)?n:i,r!==i&&this.raise(e.start,de.MixedLabeledAndUnlabeledElements)})),this.finishNode(e,"TSTupleType")}tsParseTupleElementType(){const{start:e,startLoc:t}=this.state,r=this.eat(p.ellipsis);let n=this.tsParseType();const s=this.eat(p.question);if(this.eat(p.colon)){const e=this.startNodeAtNode(n);e.optional=s,"TSTypeReference"!==n.type||n.typeParameters||"Identifier"!==n.typeName.type?(this.raise(n.start,de.InvalidTupleMemberLabel),e.label=n):e.label=n.typeName,e.elementType=this.tsParseType(),n=this.finishNode(e,"TSNamedTupleMember")}else if(s){const e=this.startNodeAtNode(n);e.typeAnnotation=n,n=this.finishNode(e,"TSOptionalType")}if(r){const r=this.startNodeAt(e,t);r.typeAnnotation=n,n=this.finishNode(r,"TSRestType")}return n}tsParseParenthesizedType(){const e=this.startNode();return this.expect(p.parenL),e.typeAnnotation=this.tsParseType(),this.expect(p.parenR),this.finishNode(e,"TSParenthesizedType")}tsParseFunctionOrConstructorType(e,t){const r=this.startNode();return"TSConstructorType"===e&&(r.abstract=!!t,t&&this.next(),this.next()),this.tsFillSignature(p.arrow,r),this.finishNode(r,e)}tsParseLiteralTypeNode(){const e=this.startNode();return e.literal=(()=>{switch(this.state.type){case p.num:case p.bigint:case p.string:case p._true:case p._false:return this.parseExprAtom();default:throw this.unexpected()}})(),this.finishNode(e,"TSLiteralType")}tsParseTemplateLiteralType(){const e=this.startNode();return e.literal=this.parseTemplate(!1),this.finishNode(e,"TSLiteralType")}parseTemplateSubstitution(){return this.state.inType?this.tsParseType():super.parseTemplateSubstitution()}tsParseThisTypeOrThisTypePredicate(){const e=this.tsParseThisTypeNode();return this.isContextual("is")&&!this.hasPrecedingLineBreak()?this.tsParseThisTypePredicate(e):e}tsParseNonArrayType(){switch(this.state.type){case p.name:case p._void:case p._null:{const e=this.match(p._void)?"TSVoidKeyword":this.match(p._null)?"TSNullKeyword":function(e){switch(e){case"any":return"TSAnyKeyword";case"boolean":return"TSBooleanKeyword";case"bigint":return"TSBigIntKeyword";case"never":return"TSNeverKeyword";case"number":return"TSNumberKeyword";case"object":return"TSObjectKeyword";case"string":return"TSStringKeyword";case"symbol":return"TSSymbolKeyword";case"undefined":return"TSUndefinedKeyword";case"unknown":return"TSUnknownKeyword";default:return}}(this.state.value);if(void 0!==e&&46!==this.lookaheadCharCode()){const t=this.startNode();return this.next(),this.finishNode(t,e)}return this.tsParseTypeReference()}case p.string:case p.num:case p.bigint:case p._true:case p._false:return this.tsParseLiteralTypeNode();case p.plusMin:if("-"===this.state.value){const e=this.startNode(),t=this.lookahead();if(t.type!==p.num&&t.type!==p.bigint)throw this.unexpected();return e.literal=this.parseMaybeUnary(),this.finishNode(e,"TSLiteralType")}break;case p._this:return this.tsParseThisTypeOrThisTypePredicate();case p._typeof:return this.tsParseTypeQuery();case p._import:return this.tsParseImportType();case p.braceL:return this.tsLookAhead(this.tsIsStartOfMappedType.bind(this))?this.tsParseMappedType():this.tsParseTypeLiteral();case p.bracketL:return this.tsParseTupleType();case p.parenL:return this.tsParseParenthesizedType();case p.backQuote:return this.tsParseTemplateLiteralType()}throw this.unexpected()}tsParseArrayTypeOrHigher(){let e=this.tsParseNonArrayType();for(;!this.hasPrecedingLineBreak()&&this.eat(p.bracketL);)if(this.match(p.bracketR)){const t=this.startNodeAtNode(e);t.elementType=e,this.expect(p.bracketR),e=this.finishNode(t,"TSArrayType")}else{const t=this.startNodeAtNode(e);t.objectType=e,t.indexType=this.tsParseType(),this.expect(p.bracketR),e=this.finishNode(t,"TSIndexedAccessType")}return e}tsParseTypeOperator(e){const t=this.startNode();return this.expectContextual(e),t.operator=e,t.typeAnnotation=this.tsParseTypeOperatorOrHigher(),"readonly"===e&&this.tsCheckTypeAnnotationForReadOnly(t),this.finishNode(t,"TSTypeOperator")}tsCheckTypeAnnotationForReadOnly(e){switch(e.typeAnnotation.type){case"TSTupleType":case"TSArrayType":return;default:this.raise(e.start,de.UnexpectedReadonly)}}tsParseInferType(){const e=this.startNode();this.expectContextual("infer");const t=this.startNode();return t.name=this.parseIdentifierName(t.start),e.typeParameter=this.finishNode(t,"TSTypeParameter"),this.finishNode(e,"TSInferType")}tsParseTypeOperatorOrHigher(){const e=["keyof","unique","readonly"].find((e=>this.isContextual(e)));return e?this.tsParseTypeOperator(e):this.isContextual("infer")?this.tsParseInferType():this.tsParseArrayTypeOrHigher()}tsParseUnionOrIntersectionType(e,t,r){const n=this.startNode(),s=this.eat(r),i=[];do{i.push(t())}while(this.eat(r));return 1!==i.length||s?(n.types=i,this.finishNode(n,e)):i[0]}tsParseIntersectionTypeOrHigher(){return this.tsParseUnionOrIntersectionType("TSIntersectionType",this.tsParseTypeOperatorOrHigher.bind(this),p.bitwiseAND)}tsParseUnionTypeOrHigher(){return this.tsParseUnionOrIntersectionType("TSUnionType",this.tsParseIntersectionTypeOrHigher.bind(this),p.bitwiseOR)}tsIsStartOfFunctionType(){return!!this.isRelational("<")||this.match(p.parenL)&&this.tsLookAhead(this.tsIsUnambiguouslyStartOfFunctionType.bind(this))}tsSkipParameterStart(){if(this.match(p.name)||this.match(p._this))return this.next(),!0;if(this.match(p.braceL)){let e=1;for(this.next();e>0;)this.match(p.braceL)?++e:this.match(p.braceR)&&--e,this.next();return!0}if(this.match(p.bracketL)){let e=1;for(this.next();e>0;)this.match(p.bracketL)?++e:this.match(p.bracketR)&&--e,this.next();return!0}return!1}tsIsUnambiguouslyStartOfFunctionType(){if(this.next(),this.match(p.parenR)||this.match(p.ellipsis))return!0;if(this.tsSkipParameterStart()){if(this.match(p.colon)||this.match(p.comma)||this.match(p.question)||this.match(p.eq))return!0;if(this.match(p.parenR)&&(this.next(),this.match(p.arrow)))return!0}return!1}tsParseTypeOrTypePredicateAnnotation(e){return this.tsInType((()=>{const t=this.startNode();this.expect(e);const r=this.startNode(),n=!!this.tsTryParse(this.tsParseTypePredicateAsserts.bind(this));if(n&&this.match(p._this)){let e=this.tsParseThisTypeOrThisTypePredicate();return"TSThisType"===e.type?(r.parameterName=e,r.asserts=!0,r.typeAnnotation=null,e=this.finishNode(r,"TSTypePredicate")):(this.resetStartLocationFromNode(e,r),e.asserts=!0),t.typeAnnotation=e,this.finishNode(t,"TSTypeAnnotation")}const s=this.tsIsIdentifier()&&this.tsTryParse(this.tsParseTypePredicatePrefix.bind(this));if(!s)return n?(r.parameterName=this.parseIdentifier(),r.asserts=n,r.typeAnnotation=null,t.typeAnnotation=this.finishNode(r,"TSTypePredicate"),this.finishNode(t,"TSTypeAnnotation")):this.tsParseTypeAnnotation(!1,t);const i=this.tsParseTypeAnnotation(!1);return r.parameterName=s,r.typeAnnotation=i,r.asserts=n,t.typeAnnotation=this.finishNode(r,"TSTypePredicate"),this.finishNode(t,"TSTypeAnnotation")}))}tsTryParseTypeOrTypePredicateAnnotation(){return this.match(p.colon)?this.tsParseTypeOrTypePredicateAnnotation(p.colon):void 0}tsTryParseTypeAnnotation(){return this.match(p.colon)?this.tsParseTypeAnnotation():void 0}tsTryParseType(){return this.tsEatThenParseType(p.colon)}tsParseTypePredicatePrefix(){const e=this.parseIdentifier();if(this.isContextual("is")&&!this.hasPrecedingLineBreak())return this.next(),e}tsParseTypePredicateAsserts(){if(!this.match(p.name)||"asserts"!==this.state.value||this.hasPrecedingLineBreak())return!1;const e=this.state.containsEsc;return this.next(),!(!this.match(p.name)&&!this.match(p._this)||(e&&this.raise(this.state.lastTokStart,x.InvalidEscapedReservedWord,"asserts"),0))}tsParseTypeAnnotation(e=!0,t=this.startNode()){return this.tsInType((()=>{e&&this.expect(p.colon),t.typeAnnotation=this.tsParseType()})),this.finishNode(t,"TSTypeAnnotation")}tsParseType(){fe(this.state.inType);const e=this.tsParseNonConditionalType();if(this.hasPrecedingLineBreak()||!this.eat(p._extends))return e;const t=this.startNodeAtNode(e);return t.checkType=e,t.extendsType=this.tsParseNonConditionalType(),this.expect(p.question),t.trueType=this.tsParseType(),this.expect(p.colon),t.falseType=this.tsParseType(),this.finishNode(t,"TSConditionalType")}isAbstractConstructorSignature(){return this.isContextual("abstract")&&this.lookahead().type===p._new}tsParseNonConditionalType(){return this.tsIsStartOfFunctionType()?this.tsParseFunctionOrConstructorType("TSFunctionType"):this.match(p._new)?this.tsParseFunctionOrConstructorType("TSConstructorType"):this.isAbstractConstructorSignature()?this.tsParseFunctionOrConstructorType("TSConstructorType",!0):this.tsParseUnionTypeOrHigher()}tsParseTypeAssertion(){const e=this.startNode(),t=this.tsTryNextParseConstantContext();return e.typeAnnotation=t||this.tsNextThenParseType(),this.expectRelational(">"),e.expression=this.parseMaybeUnary(),this.finishNode(e,"TSTypeAssertion")}tsParseHeritageClause(e){const t=this.state.start,r=this.tsParseDelimitedList("HeritageClauseElement",this.tsParseExpressionWithTypeArguments.bind(this));return r.length||this.raise(t,de.EmptyHeritageClauseType,e),r}tsParseExpressionWithTypeArguments(){const e=this.startNode();return e.expression=this.tsParseEntityName(!1),this.isRelational("<")&&(e.typeParameters=this.tsParseTypeArguments()),this.finishNode(e,"TSExpressionWithTypeArguments")}tsParseInterfaceDeclaration(e){e.id=this.parseIdentifier(),this.checkLVal(e.id,"typescript interface declaration",130),e.typeParameters=this.tsTryParseTypeParameters(),this.eat(p._extends)&&(e.extends=this.tsParseHeritageClause("extends"));const t=this.startNode();return t.body=this.tsInType(this.tsParseObjectTypeMembers.bind(this)),e.body=this.finishNode(t,"TSInterfaceBody"),this.finishNode(e,"TSInterfaceDeclaration")}tsParseTypeAliasDeclaration(e){return e.id=this.parseIdentifier(),this.checkLVal(e.id,"typescript type alias",2),e.typeParameters=this.tsTryParseTypeParameters(),e.typeAnnotation=this.tsInType((()=>{if(this.expect(p.eq),this.isContextual("intrinsic")&&this.lookahead().type!==p.dot){const e=this.startNode();return this.next(),this.finishNode(e,"TSIntrinsicKeyword")}return this.tsParseType()})),this.semicolon(),this.finishNode(e,"TSTypeAliasDeclaration")}tsInNoContext(e){const t=this.state.context;this.state.context=[t[0]];try{return e()}finally{this.state.context=t}}tsInType(e){const t=this.state.inType;this.state.inType=!0;try{return e()}finally{this.state.inType=t}}tsEatThenParseType(e){return this.match(e)?this.tsNextThenParseType():void 0}tsExpectThenParseType(e){return this.tsDoThenParseType((()=>this.expect(e)))}tsNextThenParseType(){return this.tsDoThenParseType((()=>this.next()))}tsDoThenParseType(e){return this.tsInType((()=>(e(),this.tsParseType())))}tsParseEnumMember(){const e=this.startNode();return e.id=this.match(p.string)?this.parseExprAtom():this.parseIdentifier(!0),this.eat(p.eq)&&(e.initializer=this.parseMaybeAssignAllowIn()),this.finishNode(e,"TSEnumMember")}tsParseEnumDeclaration(e,t){return t&&(e.const=!0),e.id=this.parseIdentifier(),this.checkLVal(e.id,"typescript enum declaration",t?779:267),this.expect(p.braceL),e.members=this.tsParseDelimitedList("EnumMembers",this.tsParseEnumMember.bind(this)),this.expect(p.braceR),this.finishNode(e,"TSEnumDeclaration")}tsParseModuleBlock(){const e=this.startNode();return this.scope.enter(0),this.expect(p.braceL),this.parseBlockOrModuleBlockBody(e.body=[],void 0,!0,p.braceR),this.scope.exit(),this.finishNode(e,"TSModuleBlock")}tsParseModuleOrNamespaceDeclaration(e,t=!1){if(e.id=this.parseIdentifier(),t||this.checkLVal(e.id,"module or namespace declaration",1024),this.eat(p.dot)){const t=this.startNode();this.tsParseModuleOrNamespaceDeclaration(t,!0),e.body=t}else this.scope.enter(256),this.prodParam.enter(0),e.body=this.tsParseModuleBlock(),this.prodParam.exit(),this.scope.exit();return this.finishNode(e,"TSModuleDeclaration")}tsParseAmbientExternalModuleDeclaration(e){return this.isContextual("global")?(e.global=!0,e.id=this.parseIdentifier()):this.match(p.string)?e.id=this.parseExprAtom():this.unexpected(),this.match(p.braceL)?(this.scope.enter(256),this.prodParam.enter(0),e.body=this.tsParseModuleBlock(),this.prodParam.exit(),this.scope.exit()):this.semicolon(),this.finishNode(e,"TSModuleDeclaration")}tsParseImportEqualsDeclaration(e,t){e.isExport=t||!1,e.id=this.parseIdentifier(),this.checkLVal(e.id,"import equals declaration",9),this.expect(p.eq);const r=this.tsParseModuleReference();return"type"===e.importKind&&"TSExternalModuleReference"!==r.type&&this.raise(r.start,de.ImportAliasHasImportType),e.moduleReference=r,this.semicolon(),this.finishNode(e,"TSImportEqualsDeclaration")}tsIsExternalModuleReference(){return this.isContextual("require")&&40===this.lookaheadCharCode()}tsParseModuleReference(){return this.tsIsExternalModuleReference()?this.tsParseExternalModuleReference():this.tsParseEntityName(!1)}tsParseExternalModuleReference(){const e=this.startNode();if(this.expectContextual("require"),this.expect(p.parenL),!this.match(p.string))throw this.unexpected();return e.expression=this.parseExprAtom(),this.expect(p.parenR),this.finishNode(e,"TSExternalModuleReference")}tsLookAhead(e){const t=this.state.clone(),r=e();return this.state=t,r}tsTryParseAndCatch(e){const t=this.tryParse((t=>e()||t()));if(!t.aborted&&t.node)return t.error&&(this.state=t.failState),t.node}tsTryParse(e){const t=this.state.clone(),r=e();return void 0!==r&&!1!==r?r:void(this.state=t)}tsTryParseDeclare(e){if(this.isLineTerminator())return;let t,r=this.state.type;return this.isContextual("let")&&(r=p._var,t="let"),this.tsInAmbientContext((()=>{switch(r){case p._function:return e.declare=!0,this.parseFunctionStatement(e,!1,!0);case p._class:return e.declare=!0,this.parseClass(e,!0,!1);case p._const:if(this.match(p._const)&&this.isLookaheadContextual("enum"))return this.expect(p._const),this.expectContextual("enum"),this.tsParseEnumDeclaration(e,!0);case p._var:return t=t||this.state.value,this.parseVarStatement(e,t);case p.name:{const t=this.state.value;return"global"===t?this.tsParseAmbientExternalModuleDeclaration(e):this.tsParseDeclaration(e,t,!0)}}}))}tsTryParseExportDeclaration(){return this.tsParseDeclaration(this.startNode(),this.state.value,!0)}tsParseExpressionStatement(e,t){switch(t.name){case"declare":{const t=this.tsTryParseDeclare(e);if(t)return t.declare=!0,t;break}case"global":if(this.match(p.braceL)){this.scope.enter(256),this.prodParam.enter(0);const r=e;return r.global=!0,r.id=t,r.body=this.tsParseModuleBlock(),this.scope.exit(),this.prodParam.exit(),this.finishNode(r,"TSModuleDeclaration")}break;default:return this.tsParseDeclaration(e,t.name,!1)}}tsParseDeclaration(e,t,r){switch(t){case"abstract":if(this.tsCheckLineTerminator(r)&&(this.match(p._class)||this.match(p.name)))return this.tsParseAbstractDeclaration(e);break;case"enum":if(r||this.match(p.name))return r&&this.next(),this.tsParseEnumDeclaration(e,!1);break;case"interface":if(this.tsCheckLineTerminator(r)&&this.match(p.name))return this.tsParseInterfaceDeclaration(e);break;case"module":if(this.tsCheckLineTerminator(r)){if(this.match(p.string))return this.tsParseAmbientExternalModuleDeclaration(e);if(this.match(p.name))return this.tsParseModuleOrNamespaceDeclaration(e)}break;case"namespace":if(this.tsCheckLineTerminator(r)&&this.match(p.name))return this.tsParseModuleOrNamespaceDeclaration(e);break;case"type":if(this.tsCheckLineTerminator(r)&&this.match(p.name))return this.tsParseTypeAliasDeclaration(e)}}tsCheckLineTerminator(e){return e?!this.hasFollowingLineBreak()&&(this.next(),!0):!this.isLineTerminator()}tsTryParseGenericAsyncArrowFunction(e,t){if(!this.isRelational("<"))return;const r=this.state.maybeInArrowParameters;this.state.maybeInArrowParameters=!0;const n=this.tsTryParseAndCatch((()=>{const r=this.startNodeAt(e,t);return r.typeParameters=this.tsParseTypeParameters(),super.parseFunctionParams(r),r.returnType=this.tsTryParseTypeOrTypePredicateAnnotation(),this.expect(p.arrow),r}));return this.state.maybeInArrowParameters=r,n?this.parseArrowExpression(n,null,!0):void 0}tsParseTypeArguments(){const e=this.startNode();return e.params=this.tsInType((()=>this.tsInNoContext((()=>(this.expectRelational("<"),this.tsParseDelimitedList("TypeParametersOrArguments",this.tsParseType.bind(this))))))),0===e.params.length&&this.raise(e.start,de.EmptyTypeArguments),this.expectRelational(">"),this.finishNode(e,"TSTypeParameterInstantiation")}tsIsDeclarationStart(){if(this.match(p.name))switch(this.state.value){case"abstract":case"declare":case"enum":case"interface":case"module":case"namespace":case"type":return!0}return!1}isExportDefaultSpecifier(){return!this.tsIsDeclarationStart()&&super.isExportDefaultSpecifier()}parseAssignableListItem(e,t){const r=this.state.start,n=this.state.startLoc;let s,i=!1,o=!1;if(void 0!==e){const t={};this.tsParseModifiers(t,["public","private","protected","override","readonly"]),s=t.accessibility,o=t.override,i=t.readonly,!1===e&&(s||i||o)&&this.raise(r,de.UnexpectedParameterModifier)}const a=this.parseMaybeDefault();this.parseAssignableListItemTypes(a);const l=this.parseMaybeDefault(a.start,a.loc.start,a);if(s||i||o){const e=this.startNodeAt(r,n);return t.length&&(e.decorators=t),s&&(e.accessibility=s),i&&(e.readonly=i),o&&(e.override=o),"Identifier"!==l.type&&"AssignmentPattern"!==l.type&&this.raise(e.start,de.UnsupportedParameterPropertyKind),e.parameter=l,this.finishNode(e,"TSParameterProperty")}return t.length&&(a.decorators=t),l}parseFunctionBodyAndFinish(e,t,r=!1){this.match(p.colon)&&(e.returnType=this.tsParseTypeOrTypePredicateAnnotation(p.colon));const n="FunctionDeclaration"===t?"TSDeclareFunction":"ClassMethod"===t?"TSDeclareMethod":void 0;n&&!this.match(p.braceL)&&this.isLineTerminator()?this.finishNode(e,n):"TSDeclareFunction"===n&&this.state.isAmbientContext&&(this.raise(e.start,de.DeclareFunctionHasImplementation),e.declare)?super.parseFunctionBodyAndFinish(e,n,r):super.parseFunctionBodyAndFinish(e,t,r)}registerFunctionStatementId(e){!e.body&&e.id?this.checkLVal(e.id,"function name",1024):super.registerFunctionStatementId(...arguments)}tsCheckForInvalidTypeCasts(e){e.forEach((e=>{"TSTypeCastExpression"===(null==e?void 0:e.type)&&this.raise(e.typeAnnotation.start,de.UnexpectedTypeAnnotation)}))}toReferencedList(e,t){return this.tsCheckForInvalidTypeCasts(e),e}parseArrayLike(...e){const t=super.parseArrayLike(...e);return"ArrayExpression"===t.type&&this.tsCheckForInvalidTypeCasts(t.elements),t}parseSubscript(e,t,r,n,s){if(!this.hasPrecedingLineBreak()&&this.match(p.bang)){this.state.exprAllowed=!1,this.next();const n=this.startNodeAt(t,r);return n.expression=e,this.finishNode(n,"TSNonNullExpression")}if(this.isRelational("<")){const i=this.tsTryParseAndCatch((()=>{if(!n&&this.atPossibleAsyncArrow(e)){const e=this.tsTryParseGenericAsyncArrowFunction(t,r);if(e)return e}const i=this.startNodeAt(t,r);i.callee=e;const o=this.tsParseTypeArguments();if(o){if(!n&&this.eat(p.parenL))return i.arguments=this.parseCallExpressionArguments(p.parenR,!1),this.tsCheckForInvalidTypeCasts(i.arguments),i.typeParameters=o,s.optionalChainMember&&(i.optional=!1),this.finishCallExpression(i,s.optionalChainMember);if(this.match(p.backQuote)){const n=this.parseTaggedTemplateExpression(e,t,r,s);return n.typeParameters=o,n}}this.unexpected()}));if(i)return i}return super.parseSubscript(e,t,r,n,s)}parseNewArguments(e){if(this.isRelational("<")){const t=this.tsTryParseAndCatch((()=>{const e=this.tsParseTypeArguments();return this.match(p.parenL)||this.unexpected(),e}));t&&(e.typeParameters=t)}super.parseNewArguments(e)}parseExprOp(e,t,r,n){if(pe(p._in.binop)>n&&!this.hasPrecedingLineBreak()&&this.isContextual("as")){const s=this.startNodeAt(t,r);s.expression=e;const i=this.tsTryNextParseConstantContext();return s.typeAnnotation=i||this.tsNextThenParseType(),this.finishNode(s,"TSAsExpression"),this.reScan_lt_gt(),this.parseExprOp(s,t,r,n)}return super.parseExprOp(e,t,r,n)}checkReservedWord(e,t,r,n){}checkDuplicateExports(){}parseImport(e){if(e.importKind="value",this.match(p.name)||this.match(p.star)||this.match(p.braceL)){let t=this.lookahead();if(!this.isContextual("type")||t.type===p.comma||t.type===p.name&&"from"===t.value||t.type===p.eq||(e.importKind="type",this.next(),t=this.lookahead()),this.match(p.name)&&t.type===p.eq)return this.tsParseImportEqualsDeclaration(e)}const t=super.parseImport(e);return"type"===t.importKind&&t.specifiers.length>1&&"ImportDefaultSpecifier"===t.specifiers[0].type&&this.raise(t.start,de.TypeImportCannotSpecifyDefaultAndNamed),t}parseExport(e){if(this.match(p._import))return this.next(),this.isContextual("type")&&61!==this.lookaheadCharCode()?(e.importKind="type",this.next()):e.importKind="value",this.tsParseImportEqualsDeclaration(e,!0);if(this.eat(p.eq)){const t=e;return t.expression=this.parseExpression(),this.semicolon(),this.finishNode(t,"TSExportAssignment")}if(this.eatContextual("as")){const t=e;return this.expectContextual("namespace"),t.id=this.parseIdentifier(),this.semicolon(),this.finishNode(t,"TSNamespaceExportDeclaration")}return this.isContextual("type")&&this.lookahead().type===p.braceL?(this.next(),e.exportKind="type"):e.exportKind="value",super.parseExport(e)}isAbstractClass(){return this.isContextual("abstract")&&this.lookahead().type===p._class}parseExportDefaultExpression(){if(this.isAbstractClass()){const e=this.startNode();return this.next(),e.abstract=!0,this.parseClass(e,!0,!0),e}if("interface"===this.state.value){const e=this.tsParseDeclaration(this.startNode(),this.state.value,!0);if(e)return e}return super.parseExportDefaultExpression()}parseStatementContent(e,t){if(this.state.type===p._const){const e=this.lookahead();if(e.type===p.name&&"enum"===e.value){const e=this.startNode();return this.expect(p._const),this.expectContextual("enum"),this.tsParseEnumDeclaration(e,!0)}}return super.parseStatementContent(e,t)}parseAccessModifier(){return this.tsParseModifier(["public","protected","private"])}tsHasSomeModifiers(e,t){return t.some((t=>he(t)?e.accessibility===t:!!e[t]))}parseClassMember(e,t,r){const n=["declare","private","public","protected","override","abstract","readonly"];this.tsParseModifiers(t,n.concat(["static"]));const s=()=>{const s=!!t.static;s&&this.eat(p.braceL)?(this.tsHasSomeModifiers(t,n)&&this.raise(this.state.pos,de.StaticBlockCannotHaveModifier),this.parseClassStaticBlock(e,t)):this.parseClassMemberWithIsStatic(e,t,r,s)};t.declare?this.tsInAmbientContext(s):s()}parseClassMemberWithIsStatic(e,t,r,n){const s=this.tsTryParseIndexSignature(t);if(s)return e.body.push(s),t.abstract&&this.raise(t.start,de.IndexSignatureHasAbstract),t.accessibility&&this.raise(t.start,de.IndexSignatureHasAccessibility,t.accessibility),t.declare&&this.raise(t.start,de.IndexSignatureHasDeclare),void(t.override&&this.raise(t.start,de.IndexSignatureHasOverride));!this.state.inAbstractClass&&t.abstract&&this.raise(t.start,de.NonAbstractClassHasAbstractMethod),t.override&&(r.hadSuperClass||this.raise(t.start,de.OverrideNotInSubClass)),super.parseClassMemberWithIsStatic(e,t,r,n)}parsePostMemberNameModifiers(e){this.eat(p.question)&&(e.optional=!0),e.readonly&&this.match(p.parenL)&&this.raise(e.start,de.ClassMethodHasReadonly),e.declare&&this.match(p.parenL)&&this.raise(e.start,de.ClassMethodHasDeclare)}parseExpressionStatement(e,t){return("Identifier"===t.type?this.tsParseExpressionStatement(e,t):void 0)||super.parseExpressionStatement(e,t)}shouldParseExportDeclaration(){return!!this.tsIsDeclarationStart()||super.shouldParseExportDeclaration()}parseConditional(e,t,r,n){if(!this.state.maybeInArrowParameters||!this.match(p.question))return super.parseConditional(e,t,r,n);const s=this.tryParse((()=>super.parseConditional(e,t,r)));return s.node?(s.error&&(this.state=s.failState),s.node):(s.error&&super.setOptionalParametersError(n,s.error),e)}parseParenItem(e,t,r){if(e=super.parseParenItem(e,t,r),this.eat(p.question)&&(e.optional=!0,this.resetEndLocation(e)),this.match(p.colon)){const n=this.startNodeAt(t,r);return n.expression=e,n.typeAnnotation=this.tsParseTypeAnnotation(),this.finishNode(n,"TSTypeCastExpression")}return e}parseExportDeclaration(e){const t=this.state.start,r=this.state.startLoc,n=this.eatContextual("declare");if(n&&(this.isContextual("declare")||!this.shouldParseExportDeclaration()))throw this.raise(this.state.start,de.ExpectedAmbientAfterExportDeclare);let s;return this.match(p.name)&&(s=this.tsTryParseExportDeclaration()),s||(s=super.parseExportDeclaration(e)),s&&("TSInterfaceDeclaration"===s.type||"TSTypeAliasDeclaration"===s.type||n)&&(e.exportKind="type"),s&&n&&(this.resetStartLocation(s,t,r),s.declare=!0),s}parseClassId(e,t,r){if((!t||r)&&this.isContextual("implements"))return;super.parseClassId(e,t,r,e.declare?1024:139);const n=this.tsTryParseTypeParameters();n&&(e.typeParameters=n)}parseClassPropertyAnnotation(e){!e.optional&&this.eat(p.bang)&&(e.definite=!0);const t=this.tsTryParseTypeAnnotation();t&&(e.typeAnnotation=t)}parseClassProperty(e){return this.parseClassPropertyAnnotation(e),this.state.isAmbientContext&&this.match(p.eq)&&this.raise(this.state.start,de.DeclareClassFieldHasInitializer),super.parseClassProperty(e)}parseClassPrivateProperty(e){return e.abstract&&this.raise(e.start,de.PrivateElementHasAbstract),e.accessibility&&this.raise(e.start,de.PrivateElementHasAccessibility,e.accessibility),this.parseClassPropertyAnnotation(e),super.parseClassPrivateProperty(e)}pushClassMethod(e,t,r,n,s,i){const o=this.tsTryParseTypeParameters();o&&s&&this.raise(o.start,de.ConstructorHasTypeParameters),!t.declare||"get"!==t.kind&&"set"!==t.kind||this.raise(t.start,de.DeclareAccessor,t.kind),o&&(t.typeParameters=o),super.pushClassMethod(e,t,r,n,s,i)}pushClassPrivateMethod(e,t,r,n){const s=this.tsTryParseTypeParameters();s&&(t.typeParameters=s),super.pushClassPrivateMethod(e,t,r,n)}parseClassSuper(e){super.parseClassSuper(e),e.superClass&&this.isRelational("<")&&(e.superTypeParameters=this.tsParseTypeArguments()),this.eatContextual("implements")&&(e.implements=this.tsParseHeritageClause("implements"))}parseObjPropValue(e,...t){const r=this.tsTryParseTypeParameters();r&&(e.typeParameters=r),super.parseObjPropValue(e,...t)}parseFunctionParams(e,t){const r=this.tsTryParseTypeParameters();r&&(e.typeParameters=r),super.parseFunctionParams(e,t)}parseVarId(e,t){super.parseVarId(e,t),"Identifier"===e.id.type&&this.eat(p.bang)&&(e.definite=!0);const r=this.tsTryParseTypeAnnotation();r&&(e.id.typeAnnotation=r,this.resetEndLocation(e.id))}parseAsyncArrowFromCallExpression(e,t){return this.match(p.colon)&&(e.returnType=this.tsParseTypeAnnotation()),super.parseAsyncArrowFromCallExpression(e,t)}parseMaybeAssign(...e){var t,r,n,s,i,o,a;let l,c,u,f;if(this.hasPlugin("jsx")&&(this.match(p.jsxTagStart)||this.isRelational("<"))){if(l=this.state.clone(),c=this.tryParse((()=>super.parseMaybeAssign(...e)),l),!c.error)return c.node;const{context:t}=this.state;t[t.length-1]===P.j_oTag?t.length-=2:t[t.length-1]===P.j_expr&&(t.length-=1)}if(!(null!=(t=c)&&t.error||this.isRelational("<")))return super.parseMaybeAssign(...e);l=l||this.state.clone();const d=this.tryParse((t=>{var r,n;f=this.tsParseTypeParameters();const s=super.parseMaybeAssign(...e);return("ArrowFunctionExpression"!==s.type||null!=(r=s.extra)&&r.parenthesized)&&t(),0!==(null==(n=f)?void 0:n.params.length)&&this.resetStartLocationFromNode(s,f),s.typeParameters=f,s}),l);if(!d.error&&!d.aborted)return d.node;if(!c&&(fe(!this.hasPlugin("jsx")),u=this.tryParse((()=>super.parseMaybeAssign(...e)),l),!u.error))return u.node;if(null!=(r=c)&&r.node)return this.state=c.failState,c.node;if(d.node)return this.state=d.failState,d.node;if(null!=(n=u)&&n.node)return this.state=u.failState,u.node;if(null!=(s=c)&&s.thrown)throw c.error;if(d.thrown)throw d.error;if(null!=(i=u)&&i.thrown)throw u.error;throw(null==(o=c)?void 0:o.error)||d.error||(null==(a=u)?void 0:a.error)}parseMaybeUnary(e){return!this.hasPlugin("jsx")&&this.isRelational("<")?this.tsParseTypeAssertion():super.parseMaybeUnary(e)}parseArrow(e){if(this.match(p.colon)){const t=this.tryParse((e=>{const t=this.tsParseTypeOrTypePredicateAnnotation(p.colon);return!this.canInsertSemicolon()&&this.match(p.arrow)||e(),t}));if(t.aborted)return;t.thrown||(t.error&&(this.state=t.failState),e.returnType=t.node)}return super.parseArrow(e)}parseAssignableListItemTypes(e){this.eat(p.question)&&("Identifier"===e.type||this.state.isAmbientContext||this.state.inType||this.raise(e.start,de.PatternIsOptional),e.optional=!0);const t=this.tsTryParseTypeAnnotation();return t&&(e.typeAnnotation=t),this.resetEndLocation(e),e}toAssignable(e,t=!1){switch(e.type){case"TSTypeCastExpression":return super.toAssignable(this.typeCastToParameter(e),t);case"TSParameterProperty":return super.toAssignable(e,t);case"ParenthesizedExpression":return this.toAssignableParenthesizedExpression(e,t);case"TSAsExpression":case"TSNonNullExpression":case"TSTypeAssertion":return e.expression=this.toAssignable(e.expression,t),e;default:return super.toAssignable(e,t)}}toAssignableParenthesizedExpression(e,t){switch(e.expression.type){case"TSAsExpression":case"TSNonNullExpression":case"TSTypeAssertion":case"ParenthesizedExpression":return e.expression=this.toAssignable(e.expression,t),e;default:return super.toAssignable(e,t)}}checkLVal(e,t,...r){var n;switch(e.type){case"TSTypeCastExpression":return;case"TSParameterProperty":return void this.checkLVal(e.parameter,"parameter property",...r);case"TSAsExpression":case"TSTypeAssertion":if(!(r[0]||"parenthesized expression"===t||null!=(n=e.extra)&&n.parenthesized)){this.raise(e.start,x.InvalidLhs,t);break}return void this.checkLVal(e.expression,"parenthesized expression",...r);case"TSNonNullExpression":return void this.checkLVal(e.expression,t,...r);default:return void super.checkLVal(e,t,...r)}}parseBindingAtom(){switch(this.state.type){case p._this:return this.parseIdentifier(!0);default:return super.parseBindingAtom()}}parseMaybeDecoratorArguments(e){if(this.isRelational("<")){const t=this.tsParseTypeArguments();if(this.match(p.parenL)){const r=super.parseMaybeDecoratorArguments(e);return r.typeParameters=t,r}this.unexpected(this.state.start,p.parenL)}return super.parseMaybeDecoratorArguments(e)}checkCommaAfterRest(e){this.state.isAmbientContext&&this.match(p.comma)&&this.lookaheadCharCode()===e?this.next():super.checkCommaAfterRest(e)}isClassMethod(){return this.isRelational("<")||super.isClassMethod()}isClassProperty(){return this.match(p.bang)||this.match(p.colon)||super.isClassProperty()}parseMaybeDefault(...e){const t=super.parseMaybeDefault(...e);return"AssignmentPattern"===t.type&&t.typeAnnotation&&t.right.startthis.tsParseTypeArguments()));t&&(e.typeParameters=t)}return super.jsxParseOpeningElementAfterName(e)}getGetterSetterExpectedParamCount(e){const t=super.getGetterSetterExpectedParamCount(e),r=this.getObjectOrClassMethodParams(e)[0];return r&&this.isThisParam(r)?t+1:t}parseCatchClauseParam(){const e=super.parseCatchClauseParam(),t=this.tsTryParseTypeAnnotation();return t&&(e.typeAnnotation=t,this.resetEndLocation(e)),e}tsInAmbientContext(e){const t=this.state.isAmbientContext;this.state.isAmbientContext=!0;try{return e()}finally{this.state.isAmbientContext=t}}parseClass(e,...t){const r=this.state.inAbstractClass;this.state.inAbstractClass=!!e.abstract;try{return super.parseClass(e,...t)}finally{this.state.inAbstractClass=r}}tsParseAbstractDeclaration(e){if(this.match(p._class))return e.abstract=!0,this.parseClass(e,!0,!1);if(this.isContextual("interface")){if(!this.hasFollowingLineBreak())return e.abstract=!0,this.raise(e.start,de.NonClassMethodPropertyHasAbstractModifer),this.next(),this.tsParseInterfaceDeclaration(e)}else this.unexpected(null,p._class)}parseMethod(...e){const t=super.parseMethod(...e);if(t.abstract&&(this.hasPlugin("estree")?t.value.body:t.body)){const{key:e}=t;this.raise(t.start,de.AbstractMethodHasImplementation,"Identifier"===e.type?e.name:`[${this.input.slice(e.start,e.end)}]`)}return t}shouldParseAsAmbientContext(){return!!this.getPluginOption("typescript","dts")}parse(){return this.shouldParseAsAmbientContext()&&(this.state.isAmbientContext=!0),super.parse()}getExpression(){return this.shouldParseAsAmbientContext()&&(this.state.isAmbientContext=!0),super.getExpression()}},v8intrinsic:e=>class extends e{parseV8Intrinsic(){if(this.match(p.modulo)){const e=this.state.start,t=this.startNode();if(this.eat(p.modulo),this.match(p.name)){const e=this.parseIdentifierName(this.state.start),r=this.createIdentifier(t,e);if(r.type="V8IntrinsicIdentifier",this.match(p.parenL))return r}this.unexpected(e)}}parseExprAtom(){return this.parseV8Intrinsic()||super.parseExprAtom(...arguments)}},placeholders:e=>class extends e{parsePlaceholder(e){if(this.match(p.placeholder)){const t=this.startNode();return this.next(),this.assertNoSpace("Unexpected space in placeholder."),t.name=super.parseIdentifier(!0),this.assertNoSpace("Unexpected space in placeholder."),this.expect(p.placeholder),this.finishPlaceholder(t,e)}}finishPlaceholder(e,t){const r=!(!e.expectedNode||"Placeholder"!==e.type);return e.expectedNode=t,r?e:this.finishNode(e,"Placeholder")}getTokenFromCode(e){return 37===e&&37===this.input.charCodeAt(this.state.pos+1)?this.finishOp(p.placeholder,2):super.getTokenFromCode(...arguments)}parseExprAtom(){return this.parsePlaceholder("Expression")||super.parseExprAtom(...arguments)}parseIdentifier(){return this.parsePlaceholder("Identifier")||super.parseIdentifier(...arguments)}checkReservedWord(e){void 0!==e&&super.checkReservedWord(...arguments)}parseBindingAtom(){return this.parsePlaceholder("Pattern")||super.parseBindingAtom(...arguments)}checkLVal(e){"Placeholder"!==e.type&&super.checkLVal(...arguments)}toAssignable(e){return e&&"Placeholder"===e.type&&"Expression"===e.expectedNode?(e.expectedNode="Pattern",e):super.toAssignable(...arguments)}isLet(e){return!!super.isLet(e)||!!this.isContextual("let")&&(!e&&this.lookahead().type===p.placeholder)}verifyBreakContinue(e){e.label&&"Placeholder"===e.label.type||super.verifyBreakContinue(...arguments)}parseExpressionStatement(e,t){if("Placeholder"!==t.type||t.extra&&t.extra.parenthesized)return super.parseExpressionStatement(...arguments);if(this.match(p.colon)){const r=e;return r.label=this.finishPlaceholder(t,"Identifier"),this.next(),r.body=this.parseStatement("label"),this.finishNode(r,"LabeledStatement")}return this.semicolon(),e.name=t.name,this.finishPlaceholder(e,"Statement")}parseBlock(){return this.parsePlaceholder("BlockStatement")||super.parseBlock(...arguments)}parseFunctionId(){return this.parsePlaceholder("Identifier")||super.parseFunctionId(...arguments)}parseClass(e,t,r){const n=t?"ClassDeclaration":"ClassExpression";this.next(),this.takeDecorators(e);const s=this.state.strict,i=this.parsePlaceholder("Identifier");if(i)if(this.match(p._extends)||this.match(p.placeholder)||this.match(p.braceL))e.id=i;else{if(r||!t)return e.id=null,e.body=this.finishPlaceholder(i,"ClassBody"),this.finishNode(e,n);this.unexpected(null,me.ClassNameIsRequired)}else this.parseClassId(e,t,r);return this.parseClassSuper(e),e.body=this.parsePlaceholder("ClassBody")||this.parseClassBody(!!e.superClass,s),this.finishNode(e,n)}parseExport(e){const t=this.parsePlaceholder("Identifier");if(!t)return super.parseExport(...arguments);if(!this.isContextual("from")&&!this.match(p.comma))return e.specifiers=[],e.source=null,e.declaration=this.finishPlaceholder(t,"Declaration"),this.finishNode(e,"ExportNamedDeclaration");this.expectPlugin("exportDefaultFrom");const r=this.startNode();return r.exported=t,e.specifiers=[this.finishNode(r,"ExportDefaultSpecifier")],super.parseExport(e)}isExportDefaultSpecifier(){if(this.match(p._default)){const e=this.nextTokenStart();if(this.isUnparsedContextual(e,"from")&&this.input.startsWith(p.placeholder.label,this.nextTokenStartSince(e+4)))return!0}return super.isExportDefaultSpecifier()}maybeParseExportDefaultSpecifier(e){return!!(e.specifiers&&e.specifiers.length>0)||super.maybeParseExportDefaultSpecifier(...arguments)}checkExport(e){const{specifiers:t}=e;null!=t&&t.length&&(e.specifiers=t.filter((e=>"Placeholder"===e.exported.type))),super.checkExport(e),e.specifiers=t}parseImport(e){const t=this.parsePlaceholder("Identifier");if(!t)return super.parseImport(...arguments);if(e.specifiers=[],!this.isContextual("from")&&!this.match(p.comma))return e.source=this.finishPlaceholder(t,"StringLiteral"),this.semicolon(),this.finishNode(e,"ImportDeclaration");const r=this.startNodeAtNode(t);return r.local=t,this.finishNode(r,"ImportDefaultSpecifier"),e.specifiers.push(r),this.eat(p.comma)&&(this.maybeParseStarImportSpecifier(e)||this.parseNamedImportSpecifiers(e)),this.expectContextual("from"),e.source=this.parseImportSource(),this.semicolon(),this.finishNode(e,"ImportDeclaration")}parseImportSource(){return this.parsePlaceholder("StringLiteral")||super.parseImportSource(...arguments)}}},xe=Object.keys(Ee),Se={sourceType:"script",sourceFilename:void 0,startLine:1,allowAwaitOutsideFunction:!1,allowReturnOutsideFunction:!1,allowImportExportEverywhere:!1,allowSuperOutsideMethod:!1,allowUndeclaredExports:!1,plugins:[],strictMode:null,ranges:!1,tokens:!1,createParenthesizedExpressions:!1,errorRecovery:!1};var Te=function(e){return e>=48&&e<=57};const we=new Set([103,109,115,105,121,117,100]),Pe={decBinOct:[46,66,69,79,95,98,101,111],hex:[46,88,95,120]},Ae={bin:[48,49]};Ae.oct=[...Ae.bin,50,51,52,53,54,55],Ae.dec=[...Ae.oct,56,57],Ae.hex=[...Ae.dec,65,66,67,68,69,70,97,98,99,100,101,102];class Oe{constructor(e){this.type=e.type,this.value=e.value,this.start=e.start,this.end=e.end,this.loc=new b(e.startLoc,e.endLoc)}}class Ce{constructor(){this.privateNames=new Set,this.loneAccessors=new Map,this.undefinedPrivateNames=new Map}}class Ie{constructor(e){this.stack=[],this.undefinedPrivateNames=new Map,this.raise=e}current(){return this.stack[this.stack.length-1]}enter(){this.stack.push(new Ce)}exit(){const e=this.stack.pop(),t=this.current();for(const[r,n]of Array.from(e.undefinedPrivateNames))t?t.undefinedPrivateNames.has(r)||t.undefinedPrivateNames.set(r,n):this.raise(n,x.InvalidPrivateFieldResolution,r)}declarePrivateName(e,t,r){const n=this.current();let s=n.privateNames.has(e);if(3&t){const r=s&&n.loneAccessors.get(e);if(r){const i=4&r,o=4&t;s=(3&r)==(3&t)||i!==o,s||n.loneAccessors.delete(e)}else s||n.loneAccessors.set(e,t)}s&&this.raise(r,x.PrivateNameRedeclaration,e),n.privateNames.add(e),n.undefinedPrivateNames.delete(e)}usePrivateName(e,t){let r;for(r of this.stack)if(r.privateNames.has(e))return;r?r.undefinedPrivateNames.set(e,t):this.raise(t,x.InvalidPrivateFieldResolution,e)}}class ke{constructor(e=0){this.type=void 0,this.type=e}canBeArrowParameterDeclaration(){return 2===this.type||1===this.type}isCertainlyParameterDeclaration(){return 3===this.type}}class Ne extends ke{constructor(e){super(e),this.errors=new Map}recordDeclarationError(e,t){this.errors.set(e,t)}clearDeclarationError(e){this.errors.delete(e)}iterateErrors(e){this.errors.forEach(e)}}class _e{constructor(e){this.stack=[new ke],this.raise=e}enter(e){this.stack.push(e)}exit(){this.stack.pop()}recordParameterInitializerError(e,t){const{stack:r}=this;let n=r.length-1,s=r[n];for(;!s.isCertainlyParameterDeclaration();){if(!s.canBeArrowParameterDeclaration())return;s.recordDeclarationError(e,t),s=r[--n]}this.raise(e,t)}recordParenthesizedIdentifierError(e,t){const{stack:r}=this,n=r[r.length-1];if(n.isCertainlyParameterDeclaration())this.raise(e,t);else{if(!n.canBeArrowParameterDeclaration())return;n.recordDeclarationError(e,t)}}recordAsyncArrowParametersError(e,t){const{stack:r}=this;let n=r.length-1,s=r[n];for(;s.canBeArrowParameterDeclaration();)2===s.type&&s.recordDeclarationError(e,t),s=r[--n]}validateAsPattern(){const{stack:e}=this,t=e[e.length-1];t.canBeArrowParameterDeclaration()&&t.iterateErrors(((t,r)=>{this.raise(r,t);let n=e.length-2,s=e[n];for(;s.canBeArrowParameterDeclaration();)s.clearDeclarationError(r),s=e[--n]}))}}function je(){return new ke}class De{constructor(){this.shorthandAssign=-1,this.doubleProto=-1,this.optionalParameters=-1}}class Le{constructor(e,t,r){this.type=void 0,this.start=void 0,this.end=void 0,this.loc=void 0,this.range=void 0,this.leadingComments=void 0,this.trailingComments=void 0,this.innerComments=void 0,this.extra=void 0,this.type="",this.start=t,this.end=0,this.loc=new b(r),null!=e&&e.options.ranges&&(this.range=[t,0]),null!=e&&e.filename&&(this.loc.filename=e.filename)}__clone(){const e=new Le,t=Object.keys(this);for(let r=0,n=t.length;r"ParenthesizedExpression"===e.type?Me(e.expression):e,Be={kind:"loop"},Re={kind:"switch"},Fe=/[\uD800-\uDFFF]/u,Ue=/in(?:stanceof)?/y;class $e extends class extends class extends class extends class extends class extends class extends class extends class extends class{constructor(){this.sawUnambiguousESM=!1,this.ambiguousScriptDifferentAst=!1}hasPlugin(e){return this.plugins.has(e)}getPluginOption(e,t){if(this.hasPlugin(e))return this.plugins.get(e)[t]}}{addComment(e){this.filename&&(e.loc.filename=this.filename),this.state.trailingComments.push(e),this.state.leadingComments.push(e)}adjustCommentsAfterTrailingComma(e,t,r){if(0===this.state.leadingComments.length)return;let n=null,s=t.length;for(;null===n&&s>0;)n=t[--s];if(null===n)return;for(let e=0;e0?n.trailingComments=i:void 0!==n.trailingComments&&(n.trailingComments=[])}processComment(e){if("Program"===e.type&&e.body.length>0)return;const t=this.state.commentStack;let r,n,s,i,o;if(this.state.trailingComments.length>0)this.state.trailingComments[0].start>=e.end?(s=this.state.trailingComments,this.state.trailingComments=[]):this.state.trailingComments.length=0;else if(t.length>0){const r=v(t);r.trailingComments&&r.trailingComments[0].start>=e.end&&(s=r.trailingComments,delete r.trailingComments)}for(t.length>0&&v(t).start>=e.start&&(r=t.pop());t.length>0&&v(t).start>=e.start;)n=t.pop();if(!n&&r&&(n=r),r)switch(e.type){case"ObjectExpression":this.adjustCommentsAfterTrailingComma(e,e.properties);break;case"ObjectPattern":this.adjustCommentsAfterTrailingComma(e,e.properties,!0);break;case"CallExpression":this.adjustCommentsAfterTrailingComma(e,e.arguments);break;case"ArrayExpression":this.adjustCommentsAfterTrailingComma(e,e.elements);break;case"ArrayPattern":this.adjustCommentsAfterTrailingComma(e,e.elements,!0)}else this.state.commentPreviousNode&&("ImportSpecifier"===this.state.commentPreviousNode.type&&"ImportSpecifier"!==e.type||"ExportSpecifier"===this.state.commentPreviousNode.type&&"ExportSpecifier"!==e.type)&&this.adjustCommentsAfterTrailingComma(e,[this.state.commentPreviousNode]);if(n){if(n.leadingComments)if(n!==e&&n.leadingComments.length>0&&v(n.leadingComments).end<=e.start)e.leadingComments=n.leadingComments,delete n.leadingComments;else for(i=n.leadingComments.length-2;i>=0;--i)if(n.leadingComments[i].end<=e.start){e.leadingComments=n.leadingComments.splice(0,i+1);break}}else if(this.state.leadingComments.length>0)if(v(this.state.leadingComments).end<=e.start){if(this.state.commentPreviousNode)for(o=0;o0&&(e.leadingComments=this.state.leadingComments,this.state.leadingComments=[])}else{for(i=0;ie.start);i++);const t=this.state.leadingComments.slice(0,i);t.length&&(e.leadingComments=t),s=this.state.leadingComments.slice(i),0===s.length&&(s=null)}if(this.state.commentPreviousNode=e,s)if(s.length&&s[0].start>=e.start&&v(s).end<=e.end)e.innerComments=s;else{const t=s.findIndex((t=>t.end>=e.end));t>0?(e.innerComments=s.slice(0,t),e.trailingComments=s.slice(t)):e.trailingComments=s}t.push(e)}}{getLocationForPosition(e){let t;return t=e===this.state.start?this.state.startLoc:e===this.state.lastTokStart?this.state.lastTokStartLoc:e===this.state.end?this.state.endLoc:e===this.state.lastTokEnd?this.state.lastTokEndLoc:function(e,t){let r,n=1,s=0;for(d.lastIndex=0;(r=d.exec(e))&&r.indexn[t]))+` (${s.line}:${s.column})`;if(this.options.errorRecovery){const t=this.state.errors;for(let r=t.length-1;r>=0;r--){const n=t[r];if(n.pos===e)return Object.assign(n,{message:i});if(n.posn[t]))+` (${s.line}:${s.column})`;return this._raise(Object.assign({loc:s,pos:e},t),i)}_raise(e,t){const r=new SyntaxError(t);if(Object.assign(r,e),this.options.errorRecovery)return this.isLookahead||this.state.errors.push(r),r;throw r}}{constructor(e,t){super(),this.isLookahead=void 0,this.tokens=[],this.state=new te,this.state.init(e),this.input=t,this.length=t.length,this.isLookahead=!1}pushToken(e){this.tokens.length=this.state.tokensLength,this.tokens.push(e),++this.state.tokensLength}next(){this.checkKeywordEscapes(),this.options.tokens&&this.pushToken(new Oe(this.state)),this.state.lastTokEnd=this.state.end,this.state.lastTokStart=this.state.start,this.state.lastTokEndLoc=this.state.endLoc,this.state.lastTokStartLoc=this.state.startLoc,this.nextToken()}eat(e){return!!this.match(e)&&(this.next(),!0)}match(e){return this.state.type===e}createLookaheadState(e){return{pos:e.pos,value:null,type:e.type,start:e.start,end:e.end,lastTokEnd:e.end,context:[this.curContext()],inType:e.inType}}lookahead(){const e=this.state;this.state=this.createLookaheadState(e),this.isLookahead=!0,this.nextToken(),this.isLookahead=!1;const t=this.state;return this.state=e,t}nextTokenStart(){return this.nextTokenStartSince(this.state.pos)}nextTokenStartSince(e){return m.lastIndex=e,e+m.exec(this.input)[0].length}lookaheadCharCode(){return this.input.charCodeAt(this.nextTokenStart())}codePointAtPos(e){let t=this.input.charCodeAt(e);if(55296==(64512&t)&&++ethis.raise(t,e))),this.state.strictErrors.clear())}curContext(){return this.state.context[this.state.context.length-1]}nextToken(){const e=this.curContext();e.preserveSpace||this.skipSpace(),this.state.start=this.state.pos,this.isLookahead||(this.state.startLoc=this.state.curPosition()),this.state.pos>=this.length?this.finishToken(p.eof):e===P.template?this.readTmplToken():this.getTokenFromCode(this.codePointAtPos(this.state.pos))}pushComment(e,t,r,n,s,i){const o={type:e?"CommentBlock":"CommentLine",value:t,start:r,end:n,loc:new b(s,i)};this.options.tokens&&this.pushToken(o),this.state.comments.push(o),this.addComment(o)}skipBlockComment(){let e;this.isLookahead||(e=this.state.curPosition());const t=this.state.pos,r=this.input.indexOf("*/",this.state.pos+2);if(-1===r)throw this.raise(t,x.UnterminatedComment);let n;for(this.state.pos=r+2,d.lastIndex=t;(n=d.exec(this.input))&&n.index=48&&t<=57)throw this.raise(this.state.pos,x.UnexpectedDigitAfterHash);if(123===t||91===t&&this.hasPlugin("recordAndTuple")){if(this.expectPlugin("recordAndTuple"),"hash"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,123===t?x.RecordExpressionHashIncorrectStartSyntaxType:x.TupleExpressionHashIncorrectStartSyntaxType);this.state.pos+=2,123===t?this.finishToken(p.braceHashL):this.finishToken(p.bracketHashL)}else j(t)?(++this.state.pos,this.finishToken(p.privateName,this.readWord1(t))):92===t?(++this.state.pos,this.finishToken(p.privateName,this.readWord1())):this.finishOp(p.hash,1)}readToken_dot(){const e=this.input.charCodeAt(this.state.pos+1);e>=48&&e<=57?this.readNumber(!0):46===e&&46===this.input.charCodeAt(this.state.pos+2)?(this.state.pos+=3,this.finishToken(p.ellipsis)):(++this.state.pos,this.finishToken(p.dot))}readToken_slash(){61===this.input.charCodeAt(this.state.pos+1)?this.finishOp(p.slashAssign,2):this.finishOp(p.slash,1)}readToken_interpreter(){if(0!==this.state.pos||this.length<2)return!1;let e=this.input.charCodeAt(this.state.pos+1);if(33!==e)return!1;const t=this.state.pos;for(this.state.pos+=1;!h(e)&&++this.state.pos=48&&t<=57?(++this.state.pos,this.finishToken(p.question)):(this.state.pos+=2,this.finishToken(p.questionDot))}getTokenFromCode(e){switch(e){case 46:return void this.readToken_dot();case 40:return++this.state.pos,void this.finishToken(p.parenL);case 41:return++this.state.pos,void this.finishToken(p.parenR);case 59:return++this.state.pos,void this.finishToken(p.semi);case 44:return++this.state.pos,void this.finishToken(p.comma);case 91:if(this.hasPlugin("recordAndTuple")&&124===this.input.charCodeAt(this.state.pos+1)){if("bar"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,x.TupleExpressionBarIncorrectStartSyntaxType);this.state.pos+=2,this.finishToken(p.bracketBarL)}else++this.state.pos,this.finishToken(p.bracketL);return;case 93:return++this.state.pos,void this.finishToken(p.bracketR);case 123:if(this.hasPlugin("recordAndTuple")&&124===this.input.charCodeAt(this.state.pos+1)){if("bar"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,x.RecordExpressionBarIncorrectStartSyntaxType);this.state.pos+=2,this.finishToken(p.braceBarL)}else++this.state.pos,this.finishToken(p.braceL);return;case 125:return++this.state.pos,void this.finishToken(p.braceR);case 58:return void(this.hasPlugin("functionBind")&&58===this.input.charCodeAt(this.state.pos+1)?this.finishOp(p.doubleColon,2):(++this.state.pos,this.finishToken(p.colon)));case 63:return void this.readToken_question();case 96:return++this.state.pos,void this.finishToken(p.backQuote);case 48:{const e=this.input.charCodeAt(this.state.pos+1);if(120===e||88===e)return void this.readRadixNumber(16);if(111===e||79===e)return void this.readRadixNumber(8);if(98===e||66===e)return void this.readRadixNumber(2)}case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return void this.readNumber(!1);case 34:case 39:return void this.readString(e);case 47:return void this.readToken_slash();case 37:case 42:return void this.readToken_mult_modulo(e);case 124:case 38:return void this.readToken_pipe_amp(e);case 94:return void this.readToken_caret();case 43:case 45:return void this.readToken_plus_min(e);case 60:case 62:return void this.readToken_lt_gt(e);case 61:case 33:return void this.readToken_eq_excl(e);case 126:return void this.finishOp(p.tilde,1);case 64:return++this.state.pos,void this.finishToken(p.at);case 35:return void this.readToken_numberSign();case 92:return void this.readWord();default:if(j(e))return void this.readWord(e)}throw this.raise(this.state.pos,x.InvalidOrUnexpectedToken,String.fromCodePoint(e))}finishOp(e,t){const r=this.input.slice(this.state.pos,this.state.pos+t);this.state.pos+=t,this.finishToken(e,r)}readRegexp(){const e=this.state.start+1;let t,r,{pos:n}=this.state;for(;;++n){if(n>=this.length)throw this.raise(e,x.UnterminatedRegExp);const s=this.input.charCodeAt(n);if(h(s))throw this.raise(e,x.UnterminatedRegExp);if(t)t=!1;else{if(91===s)r=!0;else if(93===s&&r)r=!1;else if(47===s&&!r)break;t=92===s}}const s=this.input.slice(e,n);++n;let i="";for(;n=97?t-97+10:t>=65?t-65+10:Te(t)?t-48:1/0,c>=e)if(this.options.errorRecovery&&c<=9)c=0,this.raise(this.state.start+s+2,x.InvalidDigit,e);else{if(!r)break;c=0,a=!0}++this.state.pos,l=l*e+c}else{const e=this.input.charCodeAt(this.state.pos-1),t=this.input.charCodeAt(this.state.pos+1);(-1===o.indexOf(t)||i.indexOf(e)>-1||i.indexOf(t)>-1||Number.isNaN(t))&&this.raise(this.state.pos,x.UnexpectedNumericSeparator),n||this.raise(this.state.pos,x.NumericSeparatorInEscapeSequence),++this.state.pos}}return this.state.pos===s||null!=t&&this.state.pos-s!==t||a?null:l}readRadixNumber(e){const t=this.state.pos;let r=!1;this.state.pos+=2;const n=this.readInt(e);null==n&&this.raise(this.state.start+2,x.InvalidDigit,e);const s=this.input.charCodeAt(this.state.pos);if(110===s)++this.state.pos,r=!0;else if(109===s)throw this.raise(t,x.InvalidDecimal);if(j(this.codePointAtPos(this.state.pos)))throw this.raise(this.state.pos,x.NumberIdentifier);if(r){const e=this.input.slice(t,this.state.pos).replace(/[_n]/g,"");this.finishToken(p.bigint,e)}else this.finishToken(p.num,n)}readNumber(e){const t=this.state.pos;let r=!1,n=!1,s=!1,i=!1,o=!1;e||null!==this.readInt(10)||this.raise(t,x.InvalidNumber);const a=this.state.pos-t>=2&&48===this.input.charCodeAt(t);if(a){const e=this.input.slice(t,this.state.pos);if(this.recordStrictModeErrors(t,x.StrictOctalLiteral),!this.state.strict){const r=e.indexOf("_");r>0&&this.raise(r+t,x.ZeroDigitNumericSeparator)}o=a&&!/[89]/.test(e)}let l=this.input.charCodeAt(this.state.pos);if(46!==l||o||(++this.state.pos,this.readInt(10),r=!0,l=this.input.charCodeAt(this.state.pos)),69!==l&&101!==l||o||(l=this.input.charCodeAt(++this.state.pos),43!==l&&45!==l||++this.state.pos,null===this.readInt(10)&&this.raise(t,x.InvalidOrMissingExponent),r=!0,i=!0,l=this.input.charCodeAt(this.state.pos)),110===l&&((r||a)&&this.raise(t,x.InvalidBigIntLiteral),++this.state.pos,n=!0),109===l&&(this.expectPlugin("decimal",this.state.pos),(i||a)&&this.raise(t,x.InvalidDecimal),++this.state.pos,s=!0),j(this.codePointAtPos(this.state.pos)))throw this.raise(this.state.pos,x.NumberIdentifier);const c=this.input.slice(t,this.state.pos).replace(/[_mn]/g,"");if(n)return void this.finishToken(p.bigint,c);if(s)return void this.finishToken(p.decimal,c);const u=o?parseInt(c,8):parseFloat(c);this.finishToken(p.num,u)}readCodePoint(e){let t;if(123===this.input.charCodeAt(this.state.pos)){const r=++this.state.pos;if(t=this.readHexChar(this.input.indexOf("}",this.state.pos)-this.state.pos,!0,e),++this.state.pos,null!==t&&t>1114111){if(!e)return null;this.raise(r,x.InvalidCodePoint)}}else t=this.readHexChar(4,!1,e);return t}readString(e){let t="",r=++this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,x.UnterminatedString);const n=this.input.charCodeAt(this.state.pos);if(n===e)break;if(92===n)t+=this.input.slice(r,this.state.pos),t+=this.readEscapedChar(!1),r=this.state.pos;else if(8232===n||8233===n)++this.state.pos,++this.state.curLine,this.state.lineStart=this.state.pos;else{if(h(n))throw this.raise(this.state.start,x.UnterminatedString);++this.state.pos}}t+=this.input.slice(r,this.state.pos++),this.finishToken(p.string,t)}readTmplToken(){let e="",t=this.state.pos,r=!1;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,x.UnterminatedTemplate);const n=this.input.charCodeAt(this.state.pos);if(96===n||36===n&&123===this.input.charCodeAt(this.state.pos+1))return this.state.pos===this.state.start&&this.match(p.template)?36===n?(this.state.pos+=2,void this.finishToken(p.dollarBraceL)):(++this.state.pos,void this.finishToken(p.backQuote)):(e+=this.input.slice(t,this.state.pos),void this.finishToken(p.template,r?null:e));if(92===n){e+=this.input.slice(t,this.state.pos);const n=this.readEscapedChar(!0);null===n?r=!0:e+=n,t=this.state.pos}else if(h(n)){switch(e+=this.input.slice(t,this.state.pos),++this.state.pos,n){case 13:10===this.input.charCodeAt(this.state.pos)&&++this.state.pos;case 10:e+="\n";break;default:e+=String.fromCharCode(n)}++this.state.curLine,this.state.lineStart=this.state.pos,t=this.state.pos}else++this.state.pos}}recordStrictModeErrors(e,t){this.state.strict&&!this.state.strictErrors.has(e)?this.raise(e,t):this.state.strictErrors.set(e,t)}readEscapedChar(e){const t=!e,r=this.input.charCodeAt(++this.state.pos);switch(++this.state.pos,r){case 110:return"\n";case 114:return"\r";case 120:{const e=this.readHexChar(2,!1,t);return null===e?null:String.fromCharCode(e)}case 117:{const e=this.readCodePoint(t);return null===e?null:String.fromCodePoint(e)}case 116:return"\t";case 98:return"\b";case 118:return"\v";case 102:return"\f";case 13:10===this.input.charCodeAt(this.state.pos)&&++this.state.pos;case 10:this.state.lineStart=this.state.pos,++this.state.curLine;case 8232:case 8233:return"";case 56:case 57:if(e)return null;this.recordStrictModeErrors(this.state.pos-1,x.StrictNumericEscape);default:if(r>=48&&r<=55){const t=this.state.pos-1;let r=this.input.substr(this.state.pos-1,3).match(/^[0-7]+/)[0],n=parseInt(r,8);n>255&&(r=r.slice(0,-1),n=parseInt(r,8)),this.state.pos+=r.length-1;const s=this.input.charCodeAt(this.state.pos);if("0"!==r||56===s||57===s){if(e)return null;this.recordStrictModeErrors(t,x.StrictNumericEscape)}return String.fromCharCode(n)}return String.fromCharCode(r)}}readHexChar(e,t,r){const n=this.state.pos,s=this.readInt(16,e,t,!1);return null===s&&(r?this.raise(n,x.InvalidEscapeSequence):this.state.pos=n-1),s}readWord1(e){this.state.containsEsc=!1;let t="";const r=this.state.pos;let n=this.state.pos;for(void 0!==e&&(this.state.pos+=e<=65535?1:2);this.state.posthis.state.lastTokEnd&&this.raise(this.state.lastTokEnd,{code:E.SyntaxError,reasonCode:"UnexpectedSpace",template:e})}unexpected(e,t={code:E.SyntaxError,reasonCode:"UnexpectedToken",template:"Unexpected token"}){throw t instanceof a&&(t={code:E.SyntaxError,reasonCode:"UnexpectedToken",template:`Unexpected token, expected "${t.label}"`}),this.raise(null!=e?e:this.state.start,t)}expectPlugin(e,t){if(!this.hasPlugin(e))throw this.raiseWithData(null!=t?t:this.state.start,{missingPlugin:[e]},`This experimental syntax requires enabling the parser plugin: '${e}'`);return!0}expectOnePlugin(e,t){if(!e.some((e=>this.hasPlugin(e))))throw this.raiseWithData(null!=t?t:this.state.start,{missingPlugin:e},`This experimental syntax requires enabling one of the following parser plugin(s): '${e.join(", ")}'`)}tryParse(e,t=this.state.clone()){const r={node:null};try{const n=e(((e=null)=>{throw r.node=e,r}));if(this.state.errors.length>t.errors.length){const e=this.state;return this.state=t,this.state.tokensLength=e.tokensLength,{node:n,error:e.errors[t.errors.length],thrown:!1,aborted:!1,failState:e}}return{node:n,error:null,thrown:!1,aborted:!1,failState:null}}catch(e){const n=this.state;if(this.state=t,e instanceof SyntaxError)return{node:null,error:e,thrown:!0,aborted:!1,failState:n};if(e===r)return{node:r.node,error:null,thrown:!1,aborted:!0,failState:n};throw e}}checkExpressionErrors(e,t){if(!e)return!1;const{shorthandAssign:r,doubleProto:n,optionalParameters:s}=e;if(!t)return r>=0||n>=0||s>=0;r>=0&&this.unexpected(r),n>=0&&this.raise(n,x.DuplicateProto),s>=0&&this.unexpected(s)}isLiteralPropertyName(){return this.match(p.name)||!!this.state.type.keyword||this.match(p.string)||this.match(p.num)||this.match(p.bigint)||this.match(p.decimal)}isPrivateName(e){return"PrivateName"===e.type}getPrivateNameSV(e){return e.id.name}hasPropertyAsPrivateName(e){return("MemberExpression"===e.type||"OptionalMemberExpression"===e.type)&&this.isPrivateName(e.property)}isOptionalChain(e){return"OptionalMemberExpression"===e.type||"OptionalCallExpression"===e.type}isObjectProperty(e){return"ObjectProperty"===e.type}isObjectMethod(e){return"ObjectMethod"===e.type}initializeScopes(e="module"===this.options.sourceType){const t=this.state.labels;this.state.labels=[];const r=this.exportedIdentifiers;this.exportedIdentifiers=new Set;const n=this.inModule;this.inModule=e;const s=this.scope,i=this.getScopeHandler();this.scope=new i(this.raise.bind(this),this.inModule);const o=this.prodParam;this.prodParam=new ce;const a=this.classScope;this.classScope=new Ie(this.raise.bind(this));const l=this.expressionScope;return this.expressionScope=new _e(this.raise.bind(this)),()=>{this.state.labels=t,this.exportedIdentifiers=r,this.inModule=n,this.scope=s,this.prodParam=o,this.classScope=a,this.expressionScope=l}}enterInitialScopes(){let e=0;this.hasPlugin("topLevelAwait")&&this.inModule&&(e|=2),this.scope.enter(1),this.prodParam.enter(e)}}{startNode(){return new Le(this,this.state.start,this.state.startLoc)}startNodeAt(e,t){return new Le(this,e,t)}startNodeAtNode(e){return this.startNodeAt(e.start,e.loc.start)}finishNode(e,t){return this.finishNodeAt(e,t,this.state.lastTokEnd,this.state.lastTokEndLoc)}finishNodeAt(e,t,r,n){return e.type=t,e.end=r,e.loc.end=n,this.options.ranges&&(e.range[1]=r),this.processComment(e),e}resetStartLocation(e,t,r){e.start=t,e.loc.start=r,this.options.ranges&&(e.range[0]=t)}resetEndLocation(e,t=this.state.lastTokEnd,r=this.state.lastTokEndLoc){e.end=t,e.loc.end=r,this.options.ranges&&(e.range[1]=t)}resetStartLocationFromNode(e,t){this.resetStartLocation(e,t.start,t.loc.start)}}{toAssignable(e,t=!1){var r,n;let s;switch(("ParenthesizedExpression"===e.type||null!=(r=e.extra)&&r.parenthesized)&&(s=Me(e),t?"Identifier"===s.type?this.expressionScope.recordParenthesizedIdentifierError(e.start,x.InvalidParenthesizedAssignment):"MemberExpression"!==s.type&&this.raise(e.start,x.InvalidParenthesizedAssignment):this.raise(e.start,x.InvalidParenthesizedAssignment)),e.type){case"Identifier":case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":break;case"ObjectExpression":e.type="ObjectPattern";for(let r=0,n=e.properties.length,s=n-1;rthis.parseExpressionBase(t))):this.allowInAnd((()=>this.parseExpressionBase(t)))}parseExpressionBase(e){const t=this.state.start,r=this.state.startLoc,n=this.parseMaybeAssign(e);if(this.match(p.comma)){const s=this.startNodeAt(t,r);for(s.expressions=[n];this.eat(p.comma);)s.expressions.push(this.parseMaybeAssign(e));return this.toReferencedList(s.expressions),this.finishNode(s,"SequenceExpression")}return n}parseMaybeAssignDisallowIn(e,t){return this.disallowInAnd((()=>this.parseMaybeAssign(e,t)))}parseMaybeAssignAllowIn(e,t){return this.allowInAnd((()=>this.parseMaybeAssign(e,t)))}setOptionalParametersError(e,t){var r;e.optionalParameters=null!=(r=null==t?void 0:t.pos)?r:this.state.start}parseMaybeAssign(e,t){const r=this.state.start,n=this.state.startLoc;if(this.isContextual("yield")&&this.prodParam.hasYield){let e=this.parseYield();return t&&(e=t.call(this,e,r,n)),e}let s;e?s=!1:(e=new De,s=!0),(this.match(p.parenL)||this.match(p.name))&&(this.state.potentialArrowAt=this.state.start);let i=this.parseMaybeConditional(e);if(t&&(i=t.call(this,i,r,n)),this.state.type.isAssign){const t=this.startNodeAt(r,n),s=this.state.value;return t.operator=s,this.match(p.eq)?(t.left=this.toAssignable(i,!0),e.doubleProto=-1):t.left=i,e.shorthandAssign>=t.left.start&&(e.shorthandAssign=-1),this.checkLVal(i,"assignment expression"),this.next(),t.right=this.parseMaybeAssign(),this.finishNode(t,"AssignmentExpression")}return s&&this.checkExpressionErrors(e,!0),i}parseMaybeConditional(e){const t=this.state.start,r=this.state.startLoc,n=this.state.potentialArrowAt,s=this.parseExprOps(e);return this.shouldExitDescending(s,n)?s:this.parseConditional(s,t,r,e)}parseConditional(e,t,r,n){if(this.eat(p.question)){const n=this.startNodeAt(t,r);return n.test=e,n.consequent=this.parseMaybeAssignAllowIn(),this.expect(p.colon),n.alternate=this.parseMaybeAssign(),this.finishNode(n,"ConditionalExpression")}return e}parseExprOps(e){const t=this.state.start,r=this.state.startLoc,n=this.state.potentialArrowAt,s=this.parseMaybeUnary(e);return this.shouldExitDescending(s,n)?s:this.parseExprOp(s,t,r,-1)}parseExprOp(e,t,r,n){let s=this.state.type.binop;if(null!=s&&(this.prodParam.hasIn||!this.match(p._in))&&s>n){const i=this.state.type;if(i===p.pipeline){if(this.expectPlugin("pipelineOperator"),this.state.inFSharpPipelineDirectBody)return e;this.state.inPipeline=!0,this.checkPipelineAtInfixOperator(e,t)}const o=this.startNodeAt(t,r);o.left=e,o.operator=this.state.value;const a=i===p.logicalOR||i===p.logicalAND,l=i===p.nullishCoalescing;if(l&&(s=p.logicalAND.binop),this.next(),i===p.pipeline&&"minimal"===this.getPluginOption("pipelineOperator","proposal")&&this.match(p.name)&&"await"===this.state.value&&this.prodParam.hasAwait)throw this.raise(this.state.start,x.UnexpectedAwaitAfterPipelineBody);o.right=this.parseExprOpRightExpr(i,s),this.finishNode(o,a||l?"LogicalExpression":"BinaryExpression");const c=this.state.type;if(l&&(c===p.logicalOR||c===p.logicalAND)||a&&c===p.nullishCoalescing)throw this.raise(this.state.start,x.MixingCoalesceWithLogical);return this.parseExprOp(o,t,r,n)}return e}parseExprOpRightExpr(e,t){const r=this.state.start,n=this.state.startLoc;switch(e){case p.pipeline:switch(this.getPluginOption("pipelineOperator","proposal")){case"smart":return this.withTopicPermittingContext((()=>this.parseSmartPipelineBody(this.parseExprOpBaseRightExpr(e,t),r,n)));case"fsharp":return this.withSoloAwaitPermittingContext((()=>this.parseFSharpPipelineBody(t)))}default:return this.parseExprOpBaseRightExpr(e,t)}}parseExprOpBaseRightExpr(e,t){const r=this.state.start,n=this.state.startLoc;return this.parseExprOp(this.parseMaybeUnary(),r,n,e.rightAssociative?t-1:t)}checkExponentialAfterUnary(e){this.match(p.exponent)&&this.raise(e.argument.start,x.UnexpectedTokenUnaryExponentiation)}parseMaybeUnary(e,t){const r=this.state.start,n=this.state.startLoc,s=this.isContextual("await");if(s&&this.isAwaitAllowed()){this.next();const e=this.parseAwait(r,n);return t||this.checkExponentialAfterUnary(e),e}if(this.isContextual("module")&&123===this.lookaheadCharCode()&&!this.hasFollowingLineBreak())return this.parseModuleExpression();const i=this.match(p.incDec),o=this.startNode();if(this.state.type.prefix){o.operator=this.state.value,o.prefix=!0,this.match(p._throw)&&this.expectPlugin("throwExpressions");const r=this.match(p._delete);if(this.next(),o.argument=this.parseMaybeUnary(null,!0),this.checkExpressionErrors(e,!0),this.state.strict&&r){const e=o.argument;"Identifier"===e.type?this.raise(o.start,x.StrictDelete):this.hasPropertyAsPrivateName(e)&&this.raise(o.start,x.DeletePrivateField)}if(!i)return t||this.checkExponentialAfterUnary(o),this.finishNode(o,"UnaryExpression")}const a=this.parseUpdate(o,i,e);return s&&(this.hasPlugin("v8intrinsic")?this.state.type.startsExpr:this.state.type.startsExpr&&!this.match(p.modulo))&&!this.isAmbiguousAwait()?(this.raiseOverwrite(r,this.hasPlugin("topLevelAwait")?x.AwaitNotInAsyncContext:x.AwaitNotInAsyncFunction),this.parseAwait(r,n)):a}parseUpdate(e,t,r){if(t)return this.checkLVal(e.argument,"prefix operation"),this.finishNode(e,"UpdateExpression");const n=this.state.start,s=this.state.startLoc;let i=this.parseExprSubscripts(r);if(this.checkExpressionErrors(r,!1))return i;for(;this.state.type.postfix&&!this.canInsertSemicolon();){const e=this.startNodeAt(n,s);e.operator=this.state.value,e.prefix=!1,e.argument=i,this.checkLVal(i,"postfix operation"),this.next(),i=this.finishNode(e,"UpdateExpression")}return i}parseExprSubscripts(e){const t=this.state.start,r=this.state.startLoc,n=this.state.potentialArrowAt,s=this.parseExprAtom(e);return this.shouldExitDescending(s,n)?s:this.parseSubscripts(s,t,r)}parseSubscripts(e,t,r,n){const s={optionalChainMember:!1,maybeAsyncArrow:this.atPossibleAsyncArrow(e),stop:!1};do{e=this.parseSubscript(e,t,r,n,s),s.maybeAsyncArrow=!1}while(!s.stop);return e}parseSubscript(e,t,r,n,s){if(!n&&this.eat(p.doubleColon))return this.parseBind(e,t,r,n,s);if(this.match(p.backQuote))return this.parseTaggedTemplateExpression(e,t,r,s);let i=!1;if(this.match(p.questionDot)){if(n&&40===this.lookaheadCharCode())return s.stop=!0,e;s.optionalChainMember=i=!0,this.next()}return!n&&this.match(p.parenL)?this.parseCoverCallAndAsyncArrowHead(e,t,r,s,i):i||this.match(p.bracketL)||this.eat(p.dot)?this.parseMember(e,t,r,s,i):(s.stop=!0,e)}parseMember(e,t,r,n,s){const i=this.startNodeAt(t,r),o=this.eat(p.bracketL);i.object=e,i.computed=o;const a=!o&&this.match(p.privateName)&&this.state.value,l=o?this.parseExpression():a?this.parsePrivateName():this.parseIdentifier(!0);return!1!==a&&("Super"===i.object.type&&this.raise(t,x.SuperPrivateField),this.classScope.usePrivateName(a,l.start)),i.property=l,o&&this.expect(p.bracketR),n.optionalChainMember?(i.optional=s,this.finishNode(i,"OptionalMemberExpression")):this.finishNode(i,"MemberExpression")}parseBind(e,t,r,n,s){const i=this.startNodeAt(t,r);return i.object=e,i.callee=this.parseNoCallExpr(),s.stop=!0,this.parseSubscripts(this.finishNode(i,"BindExpression"),t,r,n)}parseCoverCallAndAsyncArrowHead(e,t,r,n,s){const i=this.state.maybeInArrowParameters;let o=null;this.state.maybeInArrowParameters=!0,this.next();let a=this.startNodeAt(t,r);return a.callee=e,n.maybeAsyncArrow&&(this.expressionScope.enter(new Ne(2)),o=new De),n.optionalChainMember&&(a.optional=s),a.arguments=s?this.parseCallExpressionArguments(p.parenR):this.parseCallExpressionArguments(p.parenR,"Import"===e.type,"Super"!==e.type,a,o),this.finishCallExpression(a,n.optionalChainMember),n.maybeAsyncArrow&&this.shouldParseAsyncArrow()&&!s?(n.stop=!0,this.expressionScope.validateAsPattern(),this.expressionScope.exit(),a=this.parseAsyncArrowFromCallExpression(this.startNodeAt(t,r),a)):(n.maybeAsyncArrow&&(this.checkExpressionErrors(o,!0),this.expressionScope.exit()),this.toReferencedArguments(a)),this.state.maybeInArrowParameters=i,a}toReferencedArguments(e,t){this.toReferencedListDeep(e.arguments,t)}parseTaggedTemplateExpression(e,t,r,n){const s=this.startNodeAt(t,r);return s.tag=e,s.quasi=this.parseTemplate(!0),n.optionalChainMember&&this.raise(t,x.OptionalChainingNoTemplate),this.finishNode(s,"TaggedTemplateExpression")}atPossibleAsyncArrow(e){return"Identifier"===e.type&&"async"===e.name&&this.state.lastTokEnd===e.end&&!this.canInsertSemicolon()&&e.end-e.start==5&&e.start===this.state.potentialArrowAt}finishCallExpression(e,t){if("Import"===e.callee.type)if(2===e.arguments.length&&(this.hasPlugin("moduleAttributes")||this.expectPlugin("importAssertions")),0===e.arguments.length||e.arguments.length>2)this.raise(e.start,x.ImportCallArity,this.hasPlugin("importAssertions")||this.hasPlugin("moduleAttributes")?"one or two arguments":"one argument");else for(const t of e.arguments)"SpreadElement"===t.type&&this.raise(t.start,x.ImportCallSpreadArgument);return this.finishNode(e,t?"OptionalCallExpression":"CallExpression")}parseCallExpressionArguments(e,t,r,n,s){const i=[];let o=!0;const a=this.state.inFSharpPipelineDirectBody;for(this.state.inFSharpPipelineDirectBody=!1;!this.eat(e);){if(o)o=!1;else if(this.expect(p.comma),this.match(e)){!t||this.hasPlugin("importAssertions")||this.hasPlugin("moduleAttributes")||this.raise(this.state.lastTokStart,x.ImportCallArgumentTrailingComma),n&&this.addExtra(n,"trailingComma",this.state.lastTokStart),this.next();break}i.push(this.parseExprListItem(!1,s,r))}return this.state.inFSharpPipelineDirectBody=a,i}shouldParseAsyncArrow(){return this.match(p.arrow)&&!this.canInsertSemicolon()}parseAsyncArrowFromCallExpression(e,t){var r;return this.expect(p.arrow),this.parseArrowExpression(e,t.arguments,!0,null==(r=t.extra)?void 0:r.trailingComma),e}parseNoCallExpr(){const e=this.state.start,t=this.state.startLoc;return this.parseSubscripts(this.parseExprAtom(),e,t,!0)}parseExprAtom(e){let t;switch(this.state.type){case p._super:return this.parseSuper();case p._import:return t=this.startNode(),this.next(),this.match(p.dot)?this.parseImportMetaProperty(t):(this.match(p.parenL)||this.raise(this.state.lastTokStart,x.UnsupportedImport),this.finishNode(t,"Import"));case p._this:return t=this.startNode(),this.next(),this.finishNode(t,"ThisExpression");case p.name:{const e=this.state.potentialArrowAt===this.state.start,t=this.state.containsEsc,r=this.parseIdentifier();if(!t&&"async"===r.name&&!this.canInsertSemicolon()){if(this.match(p._function))return this.next(),this.parseFunction(this.startNodeAtNode(r),void 0,!0);if(this.match(p.name))return 61===this.lookaheadCharCode()?this.parseAsyncArrowUnaryFunction(r):r;if(this.match(p._do))return this.parseDo(!0)}return e&&this.match(p.arrow)&&!this.canInsertSemicolon()?(this.next(),this.parseArrowExpression(this.startNodeAtNode(r),[r],!1)):r}case p._do:return this.parseDo(!1);case p.slash:case p.slashAssign:return this.readRegexp(),this.parseRegExpLiteral(this.state.value);case p.num:return this.parseNumericLiteral(this.state.value);case p.bigint:return this.parseBigIntLiteral(this.state.value);case p.decimal:return this.parseDecimalLiteral(this.state.value);case p.string:return this.parseStringLiteral(this.state.value);case p._null:return this.parseNullLiteral();case p._true:return this.parseBooleanLiteral(!0);case p._false:return this.parseBooleanLiteral(!1);case p.parenL:{const e=this.state.potentialArrowAt===this.state.start;return this.parseParenAndDistinguishExpression(e)}case p.bracketBarL:case p.bracketHashL:return this.parseArrayLike(this.state.type===p.bracketBarL?p.bracketBarR:p.bracketR,!1,!0,e);case p.bracketL:return this.parseArrayLike(p.bracketR,!0,!1,e);case p.braceBarL:case p.braceHashL:return this.parseObjectLike(this.state.type===p.braceBarL?p.braceBarR:p.braceR,!1,!0,e);case p.braceL:return this.parseObjectLike(p.braceR,!1,!1,e);case p._function:return this.parseFunctionOrFunctionSent();case p.at:this.parseDecorators();case p._class:return t=this.startNode(),this.takeDecorators(t),this.parseClass(t,!1);case p._new:return this.parseNewOrNewTarget();case p.backQuote:return this.parseTemplate(!1);case p.doubleColon:{t=this.startNode(),this.next(),t.object=null;const e=t.callee=this.parseNoCallExpr();if("MemberExpression"===e.type)return this.finishNode(t,"BindExpression");throw this.raise(e.start,x.UnsupportedBind)}case p.privateName:{const e=this.state.start,r=this.state.value;if(t=this.parsePrivateName(),this.match(p._in))this.expectPlugin("privateIn"),this.classScope.usePrivateName(r,t.start);else{if(!this.hasPlugin("privateIn"))throw this.unexpected(e);this.raise(this.state.start,x.PrivateInExpectedIn,r)}return t}case p.hash:if(this.state.inPipeline)return t=this.startNode(),"smart"!==this.getPluginOption("pipelineOperator","proposal")&&this.raise(t.start,x.PrimaryTopicRequiresSmartPipeline),this.next(),this.primaryTopicReferenceIsAllowedInCurrentTopicContext()||this.raise(t.start,x.PrimaryTopicNotAllowed),this.registerTopicReference(),this.finishNode(t,"PipelinePrimaryTopicReference");case p.relational:if("<"===this.state.value){const e=this.input.codePointAt(this.nextTokenStart());(j(e)||62===e)&&this.expectOnePlugin(["jsx","flow","typescript"])}default:throw this.unexpected()}}parseAsyncArrowUnaryFunction(e){const t=this.startNodeAtNode(e);this.prodParam.enter(ue(!0,this.prodParam.hasYield));const r=[this.parseIdentifier()];return this.prodParam.exit(),this.hasPrecedingLineBreak()&&this.raise(this.state.pos,x.LineTerminatorBeforeArrow),this.expect(p.arrow),this.parseArrowExpression(t,r,!0),t}parseDo(e){this.expectPlugin("doExpressions"),e&&this.expectPlugin("asyncDoExpressions");const t=this.startNode();t.async=e,this.next();const r=this.state.labels;return this.state.labels=[],e?(this.prodParam.enter(2),t.body=this.parseBlock(),this.prodParam.exit()):t.body=this.parseBlock(),this.state.labels=r,this.finishNode(t,"DoExpression")}parseSuper(){const e=this.startNode();return this.next(),!this.match(p.parenL)||this.scope.allowDirectSuper||this.options.allowSuperOutsideMethod?this.scope.allowSuper||this.options.allowSuperOutsideMethod||this.raise(e.start,x.UnexpectedSuper):this.raise(e.start,x.SuperNotAllowed),this.match(p.parenL)||this.match(p.bracketL)||this.match(p.dot)||this.raise(e.start,x.UnsupportedSuper),this.finishNode(e,"Super")}parseMaybePrivateName(e){return this.match(p.privateName)?(e||this.raise(this.state.start+1,x.UnexpectedPrivateField),this.parsePrivateName()):this.parseIdentifier(!0)}parsePrivateName(){const e=this.startNode(),t=this.startNodeAt(this.state.start+1,new g(this.state.curLine,this.state.start+1-this.state.lineStart)),r=this.state.value;return this.next(),e.id=this.createIdentifier(t,r),this.finishNode(e,"PrivateName")}parseFunctionOrFunctionSent(){const e=this.startNode();if(this.next(),this.prodParam.hasYield&&this.match(p.dot)){const t=this.createIdentifier(this.startNodeAtNode(e),"function");return this.next(),this.parseMetaProperty(e,t,"sent")}return this.parseFunction(e)}parseMetaProperty(e,t,r){e.meta=t,"function"===t.name&&"sent"===r&&(this.isContextual(r)?this.expectPlugin("functionSent"):this.hasPlugin("functionSent")||this.unexpected());const n=this.state.containsEsc;return e.property=this.parseIdentifier(!0),(e.property.name!==r||n)&&this.raise(e.property.start,x.UnsupportedMetaProperty,t.name,r),this.finishNode(e,"MetaProperty")}parseImportMetaProperty(e){const t=this.createIdentifier(this.startNodeAtNode(e),"import");return this.next(),this.isContextual("meta")&&(this.inModule||this.raise(t.start,S.ImportMetaOutsideModule),this.sawUnambiguousESM=!0),this.parseMetaProperty(e,t,"meta")}parseLiteralAtNode(e,t,r){return this.addExtra(r,"rawValue",e),this.addExtra(r,"raw",this.input.slice(r.start,this.state.end)),r.value=e,this.next(),this.finishNode(r,t)}parseLiteral(e,t){const r=this.startNode();return this.parseLiteralAtNode(e,t,r)}parseStringLiteral(e){return this.parseLiteral(e,"StringLiteral")}parseNumericLiteral(e){return this.parseLiteral(e,"NumericLiteral")}parseBigIntLiteral(e){return this.parseLiteral(e,"BigIntLiteral")}parseDecimalLiteral(e){return this.parseLiteral(e,"DecimalLiteral")}parseRegExpLiteral(e){const t=this.parseLiteral(e.value,"RegExpLiteral");return t.pattern=e.pattern,t.flags=e.flags,t}parseBooleanLiteral(e){const t=this.startNode();return t.value=e,this.next(),this.finishNode(t,"BooleanLiteral")}parseNullLiteral(){const e=this.startNode();return this.next(),this.finishNode(e,"NullLiteral")}parseParenAndDistinguishExpression(e){const t=this.state.start,r=this.state.startLoc;let n;this.next(),this.expressionScope.enter(new Ne(1));const s=this.state.maybeInArrowParameters,i=this.state.inFSharpPipelineDirectBody;this.state.maybeInArrowParameters=!0,this.state.inFSharpPipelineDirectBody=!1;const o=this.state.start,a=this.state.startLoc,l=[],c=new De;let u,f,d=!0;for(;!this.match(p.parenR);){if(d)d=!1;else if(this.expect(p.comma,-1===c.optionalParameters?null:c.optionalParameters),this.match(p.parenR)){f=this.state.start;break}if(this.match(p.ellipsis)){const e=this.state.start,t=this.state.startLoc;u=this.state.start,l.push(this.parseParenItem(this.parseRestBinding(),e,t)),this.checkCommaAfterRest(41);break}l.push(this.parseMaybeAssignAllowIn(c,this.parseParenItem))}const h=this.state.lastTokEnd,m=this.state.lastTokEndLoc;this.expect(p.parenR),this.state.maybeInArrowParameters=s,this.state.inFSharpPipelineDirectBody=i;let y=this.startNodeAt(t,r);if(e&&this.shouldParseArrow()&&(y=this.parseArrow(y)))return this.expressionScope.validateAsPattern(),this.expressionScope.exit(),this.parseArrowExpression(y,l,!1),y;if(this.expressionScope.exit(),l.length||this.unexpected(this.state.lastTokStart),f&&this.unexpected(f),u&&this.unexpected(u),this.checkExpressionErrors(c,!0),this.toReferencedListDeep(l,!0),l.length>1?(n=this.startNodeAt(o,a),n.expressions=l,this.finishNodeAt(n,"SequenceExpression",h,m)):n=l[0],!this.options.createParenthesizedExpressions)return this.addExtra(n,"parenthesized",!0),this.addExtra(n,"parenStart",t),n;const g=this.startNodeAt(t,r);return g.expression=n,this.finishNode(g,"ParenthesizedExpression"),g}shouldParseArrow(){return!this.canInsertSemicolon()}parseArrow(e){if(this.eat(p.arrow))return e}parseParenItem(e,t,r){return e}parseNewOrNewTarget(){const e=this.startNode();if(this.next(),this.match(p.dot)){const t=this.createIdentifier(this.startNodeAtNode(e),"new");this.next();const r=this.parseMetaProperty(e,t,"target");return this.scope.inNonArrowFunction||this.scope.inClass||this.raise(r.start,x.UnexpectedNewTarget),r}return this.parseNew(e)}parseNew(e){return e.callee=this.parseNoCallExpr(),"Import"===e.callee.type?this.raise(e.callee.start,x.ImportCallNotNewExpression):this.isOptionalChain(e.callee)?this.raise(this.state.lastTokEnd,x.OptionalChainingNoNew):this.eat(p.questionDot)&&this.raise(this.state.start,x.OptionalChainingNoNew),this.parseNewArguments(e),this.finishNode(e,"NewExpression")}parseNewArguments(e){if(this.eat(p.parenL)){const t=this.parseExprList(p.parenR);this.toReferencedList(t),e.arguments=t}else e.arguments=[]}parseTemplateElement(e){const t=this.startNode();return null===this.state.value&&(e||this.raise(this.state.start+1,x.InvalidEscapeSequenceTemplate)),t.value={raw:this.input.slice(this.state.start,this.state.end).replace(/\r\n?/g,"\n"),cooked:this.state.value},this.next(),t.tail=this.match(p.backQuote),this.finishNode(t,"TemplateElement")}parseTemplate(e){const t=this.startNode();this.next(),t.expressions=[];let r=this.parseTemplateElement(e);for(t.quasis=[r];!r.tail;)this.expect(p.dollarBraceL),t.expressions.push(this.parseTemplateSubstitution()),this.expect(p.braceR),t.quasis.push(r=this.parseTemplateElement(e));return this.next(),this.finishNode(t,"TemplateLiteral")}parseTemplateSubstitution(){return this.parseExpression()}parseObjectLike(e,t,r,n){r&&this.expectPlugin("recordAndTuple");const s=this.state.inFSharpPipelineDirectBody;this.state.inFSharpPipelineDirectBody=!1;const i=Object.create(null);let o=!0;const a=this.startNode();for(a.properties=[],this.next();!this.match(e);){if(o)o=!1;else if(this.expect(p.comma),this.match(e)){this.addExtra(a,"trailingComma",this.state.lastTokStart);break}const s=this.parsePropertyDefinition(t,n);t||this.checkProto(s,r,i,n),r&&!this.isObjectProperty(s)&&"SpreadElement"!==s.type&&this.raise(s.start,x.InvalidRecordProperty),s.shorthand&&this.addExtra(s,"shorthand",!0),a.properties.push(s)}this.next(),this.state.inFSharpPipelineDirectBody=s;let l="ObjectExpression";return t?l="ObjectPattern":r&&(l="RecordExpression"),this.finishNode(a,l)}maybeAsyncOrAccessorProp(e){return!e.computed&&"Identifier"===e.key.type&&(this.isLiteralPropertyName()||this.match(p.bracketL)||this.match(p.star))}parsePropertyDefinition(e,t){let r=[];if(this.match(p.at))for(this.hasPlugin("decorators")&&this.raise(this.state.start,x.UnsupportedPropertyDecorator);this.match(p.at);)r.push(this.parseDecorator());const n=this.startNode();let s,i,o=!1,a=!1,l=!1;if(this.match(p.ellipsis))return r.length&&this.unexpected(),e?(this.next(),n.argument=this.parseIdentifier(),this.checkCommaAfterRest(125),this.finishNode(n,"RestElement")):this.parseSpread();r.length&&(n.decorators=r,r=[]),n.method=!1,(e||t)&&(s=this.state.start,i=this.state.startLoc),e||(o=this.eat(p.star));const c=this.state.containsEsc,u=this.parsePropertyName(n,!1);if(!e&&!o&&!c&&this.maybeAsyncOrAccessorProp(n)){const e=u.name;"async"!==e||this.hasPrecedingLineBreak()||(a=!0,o=this.eat(p.star),this.parsePropertyName(n,!1)),"get"!==e&&"set"!==e||(l=!0,n.kind=e,this.match(p.star)&&(o=!0,this.raise(this.state.pos,x.AccessorIsGenerator,e),this.next()),this.parsePropertyName(n,!1))}return this.parseObjPropValue(n,s,i,o,a,e,l,t),n}getGetterSetterExpectedParamCount(e){return"get"===e.kind?0:1}getObjectOrClassMethodParams(e){return e.params}checkGetterSetterParams(e){var t;const r=this.getGetterSetterExpectedParamCount(e),n=this.getObjectOrClassMethodParams(e),s=e.start;n.length!==r&&("get"===e.kind?this.raise(s,x.BadGetterArity):this.raise(s,x.BadSetterArity)),"set"===e.kind&&"RestElement"===(null==(t=n[n.length-1])?void 0:t.type)&&this.raise(s,x.BadSetterRestParameter)}parseObjectMethod(e,t,r,n,s){return s?(this.parseMethod(e,t,!1,!1,!1,"ObjectMethod"),this.checkGetterSetterParams(e),e):r||t||this.match(p.parenL)?(n&&this.unexpected(),e.kind="method",e.method=!0,this.parseMethod(e,t,r,!1,!1,"ObjectMethod")):void 0}parseObjectProperty(e,t,r,n,s){return e.shorthand=!1,this.eat(p.colon)?(e.value=n?this.parseMaybeDefault(this.state.start,this.state.startLoc):this.parseMaybeAssignAllowIn(s),this.finishNode(e,"ObjectProperty")):e.computed||"Identifier"!==e.key.type?void 0:(this.checkReservedWord(e.key.name,e.key.start,!0,!1),n?e.value=this.parseMaybeDefault(t,r,e.key.__clone()):this.match(p.eq)&&s?(-1===s.shorthandAssign&&(s.shorthandAssign=this.state.start),e.value=this.parseMaybeDefault(t,r,e.key.__clone())):e.value=e.key.__clone(),e.shorthand=!0,this.finishNode(e,"ObjectProperty"))}parseObjPropValue(e,t,r,n,s,i,o,a){const l=this.parseObjectMethod(e,n,s,i,o)||this.parseObjectProperty(e,t,r,i,a);return l||this.unexpected(),l}parsePropertyName(e,t){if(this.eat(p.bracketL))e.computed=!0,e.key=this.parseMaybeAssignAllowIn(),this.expect(p.bracketR);else{const r=this.state.inPropertyName;this.state.inPropertyName=!0;const n=this.state.type;e.key=n===p.num||n===p.string||n===p.bigint||n===p.decimal?this.parseExprAtom():this.parseMaybePrivateName(t),n!==p.privateName&&(e.computed=!1),this.state.inPropertyName=r}return e.key}initFunction(e,t){e.id=null,e.generator=!1,e.async=!!t}parseMethod(e,t,r,n,s,i,o=!1){this.initFunction(e,r),e.generator=!!t;const a=n;return this.scope.enter(18|(o?64:0)|(s?32:0)),this.prodParam.enter(ue(r,e.generator)),this.parseFunctionParams(e,a),this.parseFunctionBodyAndFinish(e,i,!0),this.prodParam.exit(),this.scope.exit(),e}parseArrayLike(e,t,r,n){r&&this.expectPlugin("recordAndTuple");const s=this.state.inFSharpPipelineDirectBody;this.state.inFSharpPipelineDirectBody=!1;const i=this.startNode();return this.next(),i.elements=this.parseExprList(e,!r,n,i),this.state.inFSharpPipelineDirectBody=s,this.finishNode(i,r?"TupleExpression":"ArrayExpression")}parseArrowExpression(e,t,r,n){this.scope.enter(6);let s=ue(r,!1);!this.match(p.bracketL)&&this.prodParam.hasIn&&(s|=8),this.prodParam.enter(s),this.initFunction(e,r);const i=this.state.maybeInArrowParameters;return t&&(this.state.maybeInArrowParameters=!0,this.setArrowFunctionParameters(e,t,n)),this.state.maybeInArrowParameters=!1,this.parseFunctionBody(e,!0),this.prodParam.exit(),this.scope.exit(),this.state.maybeInArrowParameters=i,this.finishNode(e,"ArrowFunctionExpression")}setArrowFunctionParameters(e,t,r){e.params=this.toAssignableList(t,r,!1)}parseFunctionBodyAndFinish(e,t,r=!1){this.parseFunctionBody(e,!1,r),this.finishNode(e,t)}parseFunctionBody(e,t,r=!1){const n=t&&!this.match(p.braceL);if(this.expressionScope.enter(je()),n)e.body=this.parseMaybeAssign(),this.checkParams(e,!1,t,!1);else{const n=this.state.strict,s=this.state.labels;this.state.labels=[],this.prodParam.enter(4|this.prodParam.currentFlags()),e.body=this.parseBlock(!0,!1,(s=>{const i=!this.isSimpleParamList(e.params);if(s&&i){const t="method"!==e.kind&&"constructor"!==e.kind||!e.key?e.start:e.key.end;this.raise(t,x.IllegalLanguageModeDirective)}const o=!n&&this.state.strict;this.checkParams(e,!(this.state.strict||t||r||i),t,o),this.state.strict&&e.id&&this.checkLVal(e.id,"function name",65,void 0,void 0,o)})),this.prodParam.exit(),this.expressionScope.exit(),this.state.labels=s}}isSimpleParamList(e){for(let t=0,r=e.length;t10)&&function(e){return V.has(e)}(e)){if("yield"===e){if(this.prodParam.hasYield)return void this.raise(t,x.YieldBindingIdentifier)}else if("await"===e){if(this.prodParam.hasAwait)return void this.raise(t,x.AwaitBindingIdentifier);if(this.scope.inStaticBlock&&!this.scope.inNonArrowFunction)return void this.raise(t,x.AwaitBindingIdentifierInStaticBlock);this.expressionScope.recordAsyncArrowParametersError(t,x.AwaitBindingIdentifier)}else if("arguments"===e&&this.scope.inClassAndNotInNonArrowFunction)return void this.raise(t,x.ArgumentsInClass);r&&q(e)?this.raise(t,x.UnexpectedKeyword,e):(this.state.strict?n?$:F:R)(e,this.inModule)&&this.raise(t,x.UnexpectedReservedWord,e)}}isAwaitAllowed(){return!!this.prodParam.hasAwait||!(!this.options.allowAwaitOutsideFunction||this.scope.inFunction)}parseAwait(e,t){const r=this.startNodeAt(e,t);return this.expressionScope.recordParameterInitializerError(r.start,x.AwaitExpressionFormalParameter),this.eat(p.star)&&this.raise(r.start,x.ObsoleteAwaitStar),this.scope.inFunction||this.options.allowAwaitOutsideFunction||(this.isAmbiguousAwait()?this.ambiguousScriptDifferentAst=!0:this.sawUnambiguousESM=!0),this.state.soloAwait||(r.argument=this.parseMaybeUnary(null,!0)),this.finishNode(r,"AwaitExpression")}isAmbiguousAwait(){return this.hasPrecedingLineBreak()||this.match(p.plusMin)||this.match(p.parenL)||this.match(p.bracketL)||this.match(p.backQuote)||this.match(p.regexp)||this.match(p.slash)||this.hasPlugin("v8intrinsic")&&this.match(p.modulo)}parseYield(){const e=this.startNode();this.expressionScope.recordParameterInitializerError(e.start,x.YieldInParameter),this.next();let t=!1,r=null;if(!this.hasPrecedingLineBreak())switch(t=this.eat(p.star),this.state.type){case p.semi:case p.eof:case p.braceR:case p.parenR:case p.bracketR:case p.braceBarR:case p.colon:case p.comma:if(!t)break;default:r=this.parseMaybeAssign()}return e.delegate=t,e.argument=r,this.finishNode(e,"YieldExpression")}checkPipelineAtInfixOperator(e,t){"smart"===this.getPluginOption("pipelineOperator","proposal")&&"SequenceExpression"===e.type&&this.raise(t,x.PipelineHeadSequenceExpression)}parseSmartPipelineBody(e,t,r){return this.checkSmartPipelineBodyEarlyErrors(e,t),this.parseSmartPipelineBodyInStyle(e,t,r)}checkSmartPipelineBodyEarlyErrors(e,t){if(this.match(p.arrow))throw this.raise(this.state.start,x.PipelineBodyNoArrow);"SequenceExpression"===e.type&&this.raise(t,x.PipelineBodySequenceExpression)}parseSmartPipelineBodyInStyle(e,t,r){const n=this.startNodeAt(t,r),s=this.isSimpleReference(e);return s?n.callee=e:(this.topicReferenceWasUsedInCurrentTopicContext()||this.raise(t,x.PipelineTopicUnused),n.expression=e),this.finishNode(n,s?"PipelineBareFunction":"PipelineTopicExpression")}isSimpleReference(e){switch(e.type){case"MemberExpression":return!e.computed&&this.isSimpleReference(e.object);case"Identifier":return!0;default:return!1}}withTopicPermittingContext(e){const t=this.state.topicContext;this.state.topicContext={maxNumOfResolvableTopics:1,maxTopicIndex:null};try{return e()}finally{this.state.topicContext=t}}withTopicForbiddingContext(e){const t=this.state.topicContext;this.state.topicContext={maxNumOfResolvableTopics:0,maxTopicIndex:null};try{return e()}finally{this.state.topicContext=t}}withSoloAwaitPermittingContext(e){const t=this.state.soloAwait;this.state.soloAwait=!0;try{return e()}finally{this.state.soloAwait=t}}allowInAnd(e){const t=this.prodParam.currentFlags();if(8&~t){this.prodParam.enter(8|t);try{return e()}finally{this.prodParam.exit()}}return e()}disallowInAnd(e){const t=this.prodParam.currentFlags();if(8&t){this.prodParam.enter(-9&t);try{return e()}finally{this.prodParam.exit()}}return e()}registerTopicReference(){this.state.topicContext.maxTopicIndex=0}primaryTopicReferenceIsAllowedInCurrentTopicContext(){return this.state.topicContext.maxNumOfResolvableTopics>=1}topicReferenceWasUsedInCurrentTopicContext(){return null!=this.state.topicContext.maxTopicIndex&&this.state.topicContext.maxTopicIndex>=0}parseFSharpPipelineBody(e){const t=this.state.start,r=this.state.startLoc;this.state.potentialArrowAt=this.state.start;const n=this.state.inFSharpPipelineDirectBody;this.state.inFSharpPipelineDirectBody=!0;const s=this.parseExprOp(this.parseMaybeUnary(),t,r,e);return this.state.inFSharpPipelineDirectBody=n,s}parseModuleExpression(){this.expectPlugin("moduleBlocks");const e=this.startNode();this.next(),this.eat(p.braceL);const t=this.initializeScopes(!0);this.enterInitialScopes();const r=this.startNode();try{e.body=this.parseProgram(r,p.braceR,"module")}finally{t()}return this.eat(p.braceR),this.finishNode(e,"ModuleExpression")}}{parseTopLevel(e,t){return e.program=this.parseProgram(t),e.comments=this.state.comments,this.options.tokens&&(e.tokens=function(e){for(let t=0;t0)for(const[e]of Array.from(this.scope.undefinedExports)){const t=this.scope.undefinedExports.get(e);this.raise(t,x.ModuleExportUndefined,e)}return this.finishNode(e,"Program")}stmtToDirective(e){const t=e.expression,r=this.startNodeAt(t.start,t.loc.start),n=this.startNodeAt(e.start,e.loc.start),s=this.input.slice(t.start,t.end),i=r.value=s.slice(1,-1);return this.addExtra(r,"raw",s),this.addExtra(r,"rawValue",i),n.value=this.finishNodeAt(r,"DirectiveLiteral",t.end,t.loc.end),this.finishNodeAt(n,"Directive",e.end,e.loc.end)}parseInterpreterDirective(){if(!this.match(p.interpreterDirective))return null;const e=this.startNode();return e.value=this.state.value,this.next(),this.finishNode(e,"InterpreterDirective")}isLet(e){return!!this.isContextual("let")&&this.isLetKeyword(e)}isLetKeyword(e){const t=this.nextTokenStart(),r=this.codePointAtPos(t);if(92===r||91===r)return!0;if(e)return!1;if(123===r)return!0;if(j(r)){Ue.lastIndex=t;const e=Ue.exec(this.input);if(null!==e){const r=this.codePointAtPos(t+e[0].length);if(!D(r)&&92!==r)return!1}return!0}return!1}parseStatement(e,t){return this.match(p.at)&&this.parseDecorators(!0),this.parseStatementContent(e,t)}parseStatementContent(e,t){let r=this.state.type;const n=this.startNode();let s;switch(this.isLet(e)&&(r=p._var,s="let"),r){case p._break:case p._continue:return this.parseBreakContinueStatement(n,r.keyword);case p._debugger:return this.parseDebuggerStatement(n);case p._do:return this.parseDoStatement(n);case p._for:return this.parseForStatement(n);case p._function:if(46===this.lookaheadCharCode())break;return e&&(this.state.strict?this.raise(this.state.start,x.StrictFunction):"if"!==e&&"label"!==e&&this.raise(this.state.start,x.SloppyFunction)),this.parseFunctionStatement(n,!1,!e);case p._class:return e&&this.unexpected(),this.parseClass(n,!0);case p._if:return this.parseIfStatement(n);case p._return:return this.parseReturnStatement(n);case p._switch:return this.parseSwitchStatement(n);case p._throw:return this.parseThrowStatement(n);case p._try:return this.parseTryStatement(n);case p._const:case p._var:return s=s||this.state.value,e&&"var"!==s&&this.raise(this.state.start,x.UnexpectedLexicalDeclaration),this.parseVarStatement(n,s);case p._while:return this.parseWhileStatement(n);case p._with:return this.parseWithStatement(n);case p.braceL:return this.parseBlock();case p.semi:return this.parseEmptyStatement(n);case p._import:{const e=this.lookaheadCharCode();if(40===e||46===e)break}case p._export:{let e;return this.options.allowImportExportEverywhere||t||this.raise(this.state.start,x.UnexpectedImportExport),this.next(),r===p._import?(e=this.parseImport(n),"ImportDeclaration"!==e.type||e.importKind&&"value"!==e.importKind||(this.sawUnambiguousESM=!0)):(e=this.parseExport(n),("ExportNamedDeclaration"!==e.type||e.exportKind&&"value"!==e.exportKind)&&("ExportAllDeclaration"!==e.type||e.exportKind&&"value"!==e.exportKind)&&"ExportDefaultDeclaration"!==e.type||(this.sawUnambiguousESM=!0)),this.assertModuleNodeAllowed(n),e}default:if(this.isAsyncFunction())return e&&this.raise(this.state.start,x.AsyncFunctionInSingleStatementContext),this.next(),this.parseFunctionStatement(n,!0,!e)}const i=this.state.value,o=this.parseExpression();return r===p.name&&"Identifier"===o.type&&this.eat(p.colon)?this.parseLabeledStatement(n,i,o,e):this.parseExpressionStatement(n,o)}assertModuleNodeAllowed(e){this.options.allowImportExportEverywhere||this.inModule||this.raise(e.start,S.ImportOutsideModule)}takeDecorators(e){const t=this.state.decoratorStack[this.state.decoratorStack.length-1];t.length&&(e.decorators=t,this.resetStartLocationFromNode(e,t[0]),this.state.decoratorStack[this.state.decoratorStack.length-1]=[])}canHaveLeadingDecorator(){return this.match(p._class)}parseDecorators(e){const t=this.state.decoratorStack[this.state.decoratorStack.length-1];for(;this.match(p.at);){const e=this.parseDecorator();t.push(e)}if(this.match(p._export))e||this.unexpected(),this.hasPlugin("decorators")&&!this.getPluginOption("decorators","decoratorsBeforeExport")&&this.raise(this.state.start,x.DecoratorExportClass);else if(!this.canHaveLeadingDecorator())throw this.raise(this.state.start,x.UnexpectedLeadingDecorator)}parseDecorator(){this.expectOnePlugin(["decorators-legacy","decorators"]);const e=this.startNode();if(this.next(),this.hasPlugin("decorators")){this.state.decoratorStack.push([]);const t=this.state.start,r=this.state.startLoc;let n;if(this.eat(p.parenL))n=this.parseExpression(),this.expect(p.parenR);else for(n=this.parseIdentifier(!1);this.eat(p.dot);){const e=this.startNodeAt(t,r);e.object=n,e.property=this.parseIdentifier(!0),e.computed=!1,n=this.finishNode(e,"MemberExpression")}e.expression=this.parseMaybeDecoratorArguments(n),this.state.decoratorStack.pop()}else e.expression=this.parseExprSubscripts();return this.finishNode(e,"Decorator")}parseMaybeDecoratorArguments(e){if(this.eat(p.parenL)){const t=this.startNodeAtNode(e);return t.callee=e,t.arguments=this.parseCallExpressionArguments(p.parenR,!1),this.toReferencedList(t.arguments),this.finishNode(t,"CallExpression")}return e}parseBreakContinueStatement(e,t){const r="break"===t;return this.next(),this.isLineTerminator()?e.label=null:(e.label=this.parseIdentifier(),this.semicolon()),this.verifyBreakContinue(e,t),this.finishNode(e,r?"BreakStatement":"ContinueStatement")}verifyBreakContinue(e,t){const r="break"===t;let n;for(n=0;nthis.parseStatement("do"))),this.state.labels.pop(),this.expect(p._while),e.test=this.parseHeaderExpression(),this.eat(p.semi),this.finishNode(e,"DoWhileStatement")}parseForStatement(e){this.next(),this.state.labels.push(Be);let t=-1;if(this.isAwaitAllowed()&&this.eatContextual("await")&&(t=this.state.lastTokStart),this.scope.enter(0),this.expect(p.parenL),this.match(p.semi))return t>-1&&this.unexpected(t),this.parseFor(e,null);const r=this.isContextual("let"),n=r&&this.isLetKeyword();if(this.match(p._var)||this.match(p._const)||n){const r=this.startNode(),s=n?"let":this.state.value;return this.next(),this.parseVar(r,!0,s),this.finishNode(r,"VariableDeclaration"),(this.match(p._in)||this.isContextual("of"))&&1===r.declarations.length?this.parseForIn(e,r,t):(t>-1&&this.unexpected(t),this.parseFor(e,r))}const s=this.match(p.name)&&!this.state.containsEsc,i=new De,o=this.parseExpression(!0,i),a=this.isContextual("of");if(a&&(r?this.raise(o.start,x.ForOfLet):-1===t&&s&&"Identifier"===o.type&&"async"===o.name&&this.raise(o.start,x.ForOfAsync)),a||this.match(p._in)){this.toAssignable(o,!0);const r=a?"for-of statement":"for-in statement";return this.checkLVal(o,r),this.parseForIn(e,o,t)}return this.checkExpressionErrors(i,!0),t>-1&&this.unexpected(t),this.parseFor(e,o)}parseFunctionStatement(e,t,r){return this.next(),this.parseFunction(e,1|(r?0:2),t)}parseIfStatement(e){return this.next(),e.test=this.parseHeaderExpression(),e.consequent=this.parseStatement("if"),e.alternate=this.eat(p._else)?this.parseStatement("if"):null,this.finishNode(e,"IfStatement")}parseReturnStatement(e){return this.prodParam.hasReturn||this.options.allowReturnOutsideFunction||this.raise(this.state.start,x.IllegalReturn),this.next(),this.isLineTerminator()?e.argument=null:(e.argument=this.parseExpression(),this.semicolon()),this.finishNode(e,"ReturnStatement")}parseSwitchStatement(e){this.next(),e.discriminant=this.parseHeaderExpression();const t=e.cases=[];let r,n;for(this.expect(p.braceL),this.state.labels.push(Re),this.scope.enter(0);!this.match(p.braceR);)if(this.match(p._case)||this.match(p._default)){const e=this.match(p._case);r&&this.finishNode(r,"SwitchCase"),t.push(r=this.startNode()),r.consequent=[],this.next(),e?r.test=this.parseExpression():(n&&this.raise(this.state.lastTokStart,x.MultipleDefaultsInSwitch),n=!0,r.test=null),this.expect(p.colon)}else r?r.consequent.push(this.parseStatement(null)):this.unexpected();return this.scope.exit(),r&&this.finishNode(r,"SwitchCase"),this.next(),this.state.labels.pop(),this.finishNode(e,"SwitchStatement")}parseThrowStatement(e){return this.next(),this.hasPrecedingLineBreak()&&this.raise(this.state.lastTokEnd,x.NewlineAfterThrow),e.argument=this.parseExpression(),this.semicolon(),this.finishNode(e,"ThrowStatement")}parseCatchClauseParam(){const e=this.parseBindingAtom(),t="Identifier"===e.type;return this.scope.enter(t?8:0),this.checkLVal(e,"catch clause",9),e}parseTryStatement(e){if(this.next(),e.block=this.parseBlock(),e.handler=null,this.match(p._catch)){const t=this.startNode();this.next(),this.match(p.parenL)?(this.expect(p.parenL),t.param=this.parseCatchClauseParam(),this.expect(p.parenR)):(t.param=null,this.scope.enter(0)),t.body=this.withTopicForbiddingContext((()=>this.parseBlock(!1,!1))),this.scope.exit(),e.handler=this.finishNode(t,"CatchClause")}return e.finalizer=this.eat(p._finally)?this.parseBlock():null,e.handler||e.finalizer||this.raise(e.start,x.NoCatchOrFinally),this.finishNode(e,"TryStatement")}parseVarStatement(e,t){return this.next(),this.parseVar(e,!1,t),this.semicolon(),this.finishNode(e,"VariableDeclaration")}parseWhileStatement(e){return this.next(),e.test=this.parseHeaderExpression(),this.state.labels.push(Be),e.body=this.withTopicForbiddingContext((()=>this.parseStatement("while"))),this.state.labels.pop(),this.finishNode(e,"WhileStatement")}parseWithStatement(e){return this.state.strict&&this.raise(this.state.start,x.StrictWith),this.next(),e.object=this.parseHeaderExpression(),e.body=this.withTopicForbiddingContext((()=>this.parseStatement("with"))),this.finishNode(e,"WithStatement")}parseEmptyStatement(e){return this.next(),this.finishNode(e,"EmptyStatement")}parseLabeledStatement(e,t,r,n){for(const e of this.state.labels)e.name===t&&this.raise(r.start,x.LabelRedeclaration,t);const s=this.state.type.isLoop?"loop":this.match(p._switch)?"switch":null;for(let t=this.state.labels.length-1;t>=0;t--){const r=this.state.labels[t];if(r.statementStart!==e.start)break;r.statementStart=this.state.start,r.kind=s}return this.state.labels.push({name:t,kind:s,statementStart:this.state.start}),e.body=this.parseStatement(n?-1===n.indexOf("label")?n+"label":n:"label"),this.state.labels.pop(),e.label=r,this.finishNode(e,"LabeledStatement")}parseExpressionStatement(e,t){return e.expression=t,this.semicolon(),this.finishNode(e,"ExpressionStatement")}parseBlock(e=!1,t=!0,r){const n=this.startNode();return e&&this.state.strictErrors.clear(),this.expect(p.braceL),t&&this.scope.enter(0),this.parseBlockBody(n,e,!1,p.braceR,r),t&&this.scope.exit(),this.finishNode(n,"BlockStatement")}isValidDirective(e){return"ExpressionStatement"===e.type&&"StringLiteral"===e.expression.type&&!e.expression.extra.parenthesized}parseBlockBody(e,t,r,n,s){const i=e.body=[],o=e.directives=[];this.parseBlockOrModuleBlockBody(i,t?o:void 0,r,n,s)}parseBlockOrModuleBlockBody(e,t,r,n,s){const i=this.state.strict;let o=!1,a=!1;for(;!this.match(n);){const n=this.parseStatement(null,r);if(t&&!a){if(this.isValidDirective(n)){const e=this.stmtToDirective(n);t.push(e),o||"use strict"!==e.value.value||(o=!0,this.setStrict(!0));continue}a=!0,this.state.strictErrors.clear()}e.push(n)}s&&s.call(this,o),i||this.setStrict(!1),this.next()}parseFor(e,t){return e.init=t,this.semicolon(!1),e.test=this.match(p.semi)?null:this.parseExpression(),this.semicolon(!1),e.update=this.match(p.parenR)?null:this.parseExpression(),this.expect(p.parenR),e.body=this.withTopicForbiddingContext((()=>this.parseStatement("for"))),this.scope.exit(),this.state.labels.pop(),this.finishNode(e,"ForStatement")}parseForIn(e,t,r){const n=this.match(p._in);return this.next(),n?r>-1&&this.unexpected(r):e.await=r>-1,"VariableDeclaration"!==t.type||null==t.declarations[0].init||n&&!this.state.strict&&"var"===t.kind&&"Identifier"===t.declarations[0].id.type?"AssignmentPattern"===t.type&&this.raise(t.start,x.InvalidLhs,"for-loop"):this.raise(t.start,x.ForInOfLoopInitializer,n?"for-in":"for-of"),e.left=t,e.right=n?this.parseExpression():this.parseMaybeAssignAllowIn(),this.expect(p.parenR),e.body=this.withTopicForbiddingContext((()=>this.parseStatement("for"))),this.scope.exit(),this.state.labels.pop(),this.finishNode(e,n?"ForInStatement":"ForOfStatement")}parseVar(e,t,r){const n=e.declarations=[],s=this.hasPlugin("typescript");for(e.kind=r;;){const e=this.startNode();if(this.parseVarId(e,r),this.eat(p.eq)?e.init=t?this.parseMaybeAssignDisallowIn():this.parseMaybeAssignAllowIn():("const"!==r||this.match(p._in)||this.isContextual("of")?"Identifier"===e.id.type||t&&(this.match(p._in)||this.isContextual("of"))||this.raise(this.state.lastTokEnd,x.DeclarationMissingInitializer,"Complex binding patterns"):s||this.raise(this.state.lastTokEnd,x.DeclarationMissingInitializer,"Const declarations"),e.init=null),n.push(this.finishNode(e,"VariableDeclarator")),!this.eat(p.comma))break}return e}parseVarId(e,t){e.id=this.parseBindingAtom(),this.checkLVal(e.id,"variable declaration","var"===t?5:9,void 0,"var"!==t)}parseFunction(e,t=0,r=!1){const n=1&t,s=2&t,i=!(!n||4&t);this.initFunction(e,r),this.match(p.star)&&s&&this.raise(this.state.start,x.GeneratorInSingleStatementContext),e.generator=this.eat(p.star),n&&(e.id=this.parseFunctionId(i));const o=this.state.maybeInArrowParameters;return this.state.maybeInArrowParameters=!1,this.scope.enter(2),this.prodParam.enter(ue(r,e.generator)),n||(e.id=this.parseFunctionId()),this.parseFunctionParams(e,!1),this.withTopicForbiddingContext((()=>{this.parseFunctionBodyAndFinish(e,n?"FunctionDeclaration":"FunctionExpression")})),this.prodParam.exit(),this.scope.exit(),n&&!s&&this.registerFunctionStatementId(e),this.state.maybeInArrowParameters=o,e}parseFunctionId(e){return e||this.match(p.name)?this.parseIdentifier():null}parseFunctionParams(e,t){this.expect(p.parenL),this.expressionScope.enter(new ke(3)),e.params=this.parseBindingList(p.parenR,41,!1,t),this.expressionScope.exit()}registerFunctionStatementId(e){e.id&&this.scope.declareName(e.id.name,this.state.strict||e.generator||e.async?this.scope.treatFunctionsAsVar?5:9:17,e.id.start)}parseClass(e,t,r){this.next(),this.takeDecorators(e);const n=this.state.strict;return this.state.strict=!0,this.parseClassId(e,t,r),this.parseClassSuper(e),e.body=this.parseClassBody(!!e.superClass,n),this.finishNode(e,t?"ClassDeclaration":"ClassExpression")}isClassProperty(){return this.match(p.eq)||this.match(p.semi)||this.match(p.braceR)}isClassMethod(){return this.match(p.parenL)}isNonstaticConstructor(e){return!(e.computed||e.static||"constructor"!==e.key.name&&"constructor"!==e.key.value)}parseClassBody(e,t){this.classScope.enter();const r={hadConstructor:!1,hadSuperClass:e};let n=[];const s=this.startNode();if(s.body=[],this.expect(p.braceL),this.withTopicForbiddingContext((()=>{for(;!this.match(p.braceR);){if(this.eat(p.semi)){if(n.length>0)throw this.raise(this.state.lastTokEnd,x.DecoratorSemicolon);continue}if(this.match(p.at)){n.push(this.parseDecorator());continue}const e=this.startNode();n.length&&(e.decorators=n,this.resetStartLocationFromNode(e,n[0]),n=[]),this.parseClassMember(s,e,r),"constructor"===e.kind&&e.decorators&&e.decorators.length>0&&this.raise(e.start,x.DecoratorConstructor)}})),this.state.strict=t,this.next(),n.length)throw this.raise(this.state.start,x.TrailingDecorator);return this.classScope.exit(),this.finishNode(s,"ClassBody")}parseClassMemberFromModifier(e,t){const r=this.parseIdentifier(!0);if(this.isClassMethod()){const n=t;return n.kind="method",n.computed=!1,n.key=r,n.static=!1,this.pushClassMethod(e,n,!1,!1,!1,!1),!0}if(this.isClassProperty()){const n=t;return n.computed=!1,n.key=r,n.static=!1,e.body.push(this.parseClassProperty(n)),!0}return!1}parseClassMember(e,t,r){const n=this.isContextual("static");if(n){if(this.parseClassMemberFromModifier(e,t))return;if(this.eat(p.braceL))return void this.parseClassStaticBlock(e,t)}this.parseClassMemberWithIsStatic(e,t,r,n)}parseClassMemberWithIsStatic(e,t,r,n){const s=t,i=t,o=t,a=t,l=s,c=s;if(t.static=n,this.eat(p.star)){l.kind="method";const t=this.match(p.privateName);return this.parseClassElementName(l),t?void this.pushClassPrivateMethod(e,i,!0,!1):(this.isNonstaticConstructor(s)&&this.raise(s.key.start,x.ConstructorIsGenerator),void this.pushClassMethod(e,s,!0,!1,!1,!1))}const u=this.state.containsEsc,f=this.match(p.privateName),d=this.parseClassElementName(t),h="Identifier"===d.type,m=this.state.start;if(this.parsePostMemberNameModifiers(c),this.isClassMethod()){if(l.kind="method",f)return void this.pushClassPrivateMethod(e,i,!1,!1);const n=this.isNonstaticConstructor(s);let o=!1;n&&(s.kind="constructor",r.hadConstructor&&!this.hasPlugin("typescript")&&this.raise(d.start,x.DuplicateConstructor),n&&this.hasPlugin("typescript")&&t.override&&this.raise(d.start,x.OverrideOnConstructor),r.hadConstructor=!0,o=r.hadSuperClass),this.pushClassMethod(e,s,!1,!1,n,o)}else if(this.isClassProperty())f?this.pushClassPrivateProperty(e,a):this.pushClassProperty(e,o);else if(!h||"async"!==d.name||u||this.isLineTerminator())if(!h||"get"!==d.name&&"set"!==d.name||u||this.match(p.star)&&this.isLineTerminator())this.isLineTerminator()?f?this.pushClassPrivateProperty(e,a):this.pushClassProperty(e,o):this.unexpected();else{l.kind=d.name;const t=this.match(p.privateName);this.parseClassElementName(s),t?this.pushClassPrivateMethod(e,i,!1,!1):(this.isNonstaticConstructor(s)&&this.raise(s.key.start,x.ConstructorIsAccessor),this.pushClassMethod(e,s,!1,!1,!1,!1)),this.checkGetterSetterParams(s)}else{const t=this.eat(p.star);c.optional&&this.unexpected(m),l.kind="method";const r=this.match(p.privateName);this.parseClassElementName(l),this.parsePostMemberNameModifiers(c),r?this.pushClassPrivateMethod(e,i,t,!0):(this.isNonstaticConstructor(s)&&this.raise(s.key.start,x.ConstructorIsAsync),this.pushClassMethod(e,s,t,!0,!1,!1))}}parseClassElementName(e){const{type:t,value:r,start:n}=this.state;return t!==p.name&&t!==p.string||!e.static||"prototype"!==r||this.raise(n,x.StaticPrototype),t===p.privateName&&"constructor"===r&&this.raise(n,x.ConstructorClassPrivateField),this.parsePropertyName(e,!0)}parseClassStaticBlock(e,t){var r;this.expectPlugin("classStaticBlock",t.start),this.scope.enter(208);const n=this.state.labels;this.state.labels=[],this.prodParam.enter(0);const s=t.body=[];this.parseBlockOrModuleBlockBody(s,void 0,!1,p.braceR),this.prodParam.exit(),this.scope.exit(),this.state.labels=n,e.body.push(this.finishNode(t,"StaticBlock")),null!=(r=t.decorators)&&r.length&&this.raise(t.start,x.DecoratorStaticBlock)}pushClassProperty(e,t){t.computed||"constructor"!==t.key.name&&"constructor"!==t.key.value||this.raise(t.key.start,x.ConstructorClassField),e.body.push(this.parseClassProperty(t))}pushClassPrivateProperty(e,t){const r=this.parseClassPrivateProperty(t);e.body.push(r),this.classScope.declarePrivateName(this.getPrivateNameSV(r.key),0,r.key.start)}pushClassMethod(e,t,r,n,s,i){e.body.push(this.parseMethod(t,r,n,s,i,"ClassMethod",!0))}pushClassPrivateMethod(e,t,r,n){const s=this.parseMethod(t,r,n,!1,!1,"ClassPrivateMethod",!0);e.body.push(s);const i="get"===s.kind?s.static?6:2:"set"===s.kind?s.static?5:1:0;this.classScope.declarePrivateName(this.getPrivateNameSV(s.key),i,s.key.start)}parsePostMemberNameModifiers(e){}parseClassPrivateProperty(e){return this.parseInitializer(e),this.semicolon(),this.finishNode(e,"ClassPrivateProperty")}parseClassProperty(e){return this.parseInitializer(e),this.semicolon(),this.finishNode(e,"ClassProperty")}parseInitializer(e){this.scope.enter(80),this.expressionScope.enter(je()),this.prodParam.enter(0),e.value=this.eat(p.eq)?this.parseMaybeAssignAllowIn():null,this.expressionScope.exit(),this.prodParam.exit(),this.scope.exit()}parseClassId(e,t,r,n=139){this.match(p.name)?(e.id=this.parseIdentifier(),t&&this.checkLVal(e.id,"class name",n)):r||!t?e.id=null:this.unexpected(null,x.MissingClassName)}parseClassSuper(e){e.superClass=this.eat(p._extends)?this.parseExprSubscripts():null}parseExport(e){const t=this.maybeParseExportDefaultSpecifier(e),r=!t||this.eat(p.comma),n=r&&this.eatExportStar(e),s=n&&this.maybeParseExportNamespaceSpecifier(e),i=r&&(!s||this.eat(p.comma)),o=t||n;if(n&&!s)return t&&this.unexpected(),this.parseExportFrom(e,!0),this.finishNode(e,"ExportAllDeclaration");const a=this.maybeParseExportNamedSpecifiers(e);if(t&&r&&!n&&!a||s&&i&&!a)throw this.unexpected(null,p.braceL);let l;if(o||a?(l=!1,this.parseExportFrom(e,o)):l=this.maybeParseExportDeclaration(e),o||a||l)return this.checkExport(e,!0,!1,!!e.source),this.finishNode(e,"ExportNamedDeclaration");if(this.eat(p._default))return e.declaration=this.parseExportDefaultExpression(),this.checkExport(e,!0,!0),this.finishNode(e,"ExportDefaultDeclaration");throw this.unexpected(null,p.braceL)}eatExportStar(e){return this.eat(p.star)}maybeParseExportDefaultSpecifier(e){if(this.isExportDefaultSpecifier()){this.expectPlugin("exportDefaultFrom");const t=this.startNode();return t.exported=this.parseIdentifier(!0),e.specifiers=[this.finishNode(t,"ExportDefaultSpecifier")],!0}return!1}maybeParseExportNamespaceSpecifier(e){if(this.isContextual("as")){e.specifiers||(e.specifiers=[]);const t=this.startNodeAt(this.state.lastTokStart,this.state.lastTokStartLoc);return this.next(),t.exported=this.parseModuleExportName(),e.specifiers.push(this.finishNode(t,"ExportNamespaceSpecifier")),!0}return!1}maybeParseExportNamedSpecifiers(e){return!!this.match(p.braceL)&&(e.specifiers||(e.specifiers=[]),e.specifiers.push(...this.parseExportSpecifiers()),e.source=null,e.declaration=null,!0)}maybeParseExportDeclaration(e){return!!this.shouldParseExportDeclaration()&&(e.specifiers=[],e.source=null,e.declaration=this.parseExportDeclaration(e),!0)}isAsyncFunction(){if(!this.isContextual("async"))return!1;const e=this.nextTokenStart();return!f.test(this.input.slice(this.state.pos,e))&&this.isUnparsedContextual(e,"function")}parseExportDefaultExpression(){const e=this.startNode(),t=this.isAsyncFunction();if(this.match(p._function)||t)return this.next(),t&&this.next(),this.parseFunction(e,5,t);if(this.match(p._class))return this.parseClass(e,!0,!0);if(this.match(p.at))return this.hasPlugin("decorators")&&this.getPluginOption("decorators","decoratorsBeforeExport")&&this.raise(this.state.start,x.DecoratorBeforeExport),this.parseDecorators(!1),this.parseClass(e,!0,!0);if(this.match(p._const)||this.match(p._var)||this.isLet())throw this.raise(this.state.start,x.UnsupportedDefaultExport);{const e=this.parseMaybeAssignAllowIn();return this.semicolon(),e}}parseExportDeclaration(e){return this.parseStatement(null)}isExportDefaultSpecifier(){if(this.match(p.name)){const e=this.state.value;if("async"===e&&!this.state.containsEsc||"let"===e)return!1;if(("type"===e||"interface"===e)&&!this.state.containsEsc){const e=this.lookahead();if(e.type===p.name&&"from"!==e.value||e.type===p.braceL)return this.expectOnePlugin(["flow","typescript"]),!1}}else if(!this.match(p._default))return!1;const e=this.nextTokenStart(),t=this.isUnparsedContextual(e,"from");if(44===this.input.charCodeAt(e)||this.match(p.name)&&t)return!0;if(this.match(p._default)&&t){const t=this.input.charCodeAt(this.nextTokenStartSince(e+4));return 34===t||39===t}return!1}parseExportFrom(e,t){if(this.eatContextual("from")){e.source=this.parseImportSource(),this.checkExport(e);const t=this.maybeParseImportAssertions();t&&(e.assertions=t)}else t?this.unexpected():e.source=null;this.semicolon()}shouldParseExportDeclaration(){if(this.match(p.at)&&(this.expectOnePlugin(["decorators","decorators-legacy"]),this.hasPlugin("decorators"))){if(!this.getPluginOption("decorators","decoratorsBeforeExport"))return!0;this.unexpected(this.state.start,x.DecoratorBeforeExport)}return"var"===this.state.type.keyword||"const"===this.state.type.keyword||"function"===this.state.type.keyword||"class"===this.state.type.keyword||this.isLet()||this.isAsyncFunction()}checkExport(e,t,r,n){if(t)if(r){if(this.checkDuplicateExports(e,"default"),this.hasPlugin("exportDefaultFrom")){var s;const t=e.declaration;"Identifier"!==t.type||"from"!==t.name||t.end-t.start!=4||null!=(s=t.extra)&&s.parenthesized||this.raise(t.start,x.ExportDefaultFromAsIdentifier)}}else if(e.specifiers&&e.specifiers.length)for(const t of e.specifiers){const{exported:e}=t,r="Identifier"===e.type?e.name:e.value;if(this.checkDuplicateExports(t,r),!n&&t.local){const{local:e}=t;"Identifier"!==e.type?this.raise(t.start,x.ExportBindingIsString,e.value,r):(this.checkReservedWord(e.name,e.start,!0,!1),this.scope.checkLocalExport(e))}}else if(e.declaration)if("FunctionDeclaration"===e.declaration.type||"ClassDeclaration"===e.declaration.type){const t=e.declaration.id;if(!t)throw new Error("Assertion failure");this.checkDuplicateExports(e,t.name)}else if("VariableDeclaration"===e.declaration.type)for(const t of e.declaration.declarations)this.checkDeclaration(t.id);if(this.state.decoratorStack[this.state.decoratorStack.length-1].length)throw this.raise(e.start,x.UnsupportedDecoratorExport)}checkDeclaration(e){if("Identifier"===e.type)this.checkDuplicateExports(e,e.name);else if("ObjectPattern"===e.type)for(const t of e.properties)this.checkDeclaration(t);else if("ArrayPattern"===e.type)for(const t of e.elements)t&&this.checkDeclaration(t);else"ObjectProperty"===e.type?this.checkDeclaration(e.value):"RestElement"===e.type?this.checkDeclaration(e.argument):"AssignmentPattern"===e.type&&this.checkDeclaration(e.left)}checkDuplicateExports(e,t){this.exportedIdentifiers.has(t)&&this.raise(e.start,"default"===t?x.DuplicateDefaultExport:x.DuplicateExport,t),this.exportedIdentifiers.add(t)}parseExportSpecifiers(){const e=[];let t=!0;for(this.expect(p.braceL);!this.eat(p.braceR);){if(t)t=!1;else if(this.expect(p.comma),this.eat(p.braceR))break;const r=this.startNode();r.local=this.parseModuleExportName(),r.exported=this.eatContextual("as")?this.parseModuleExportName():r.local.__clone(),e.push(this.finishNode(r,"ExportSpecifier"))}return e}parseModuleExportName(){if(this.match(p.string)){const e=this.parseStringLiteral(this.state.value),t=e.value.match(Fe);return t&&this.raise(e.start,x.ModuleExportNameHasLoneSurrogate,t[0].charCodeAt(0).toString(16)),e}return this.parseIdentifier(!0)}parseImport(e){if(e.specifiers=[],!this.match(p.string)){const t=!this.maybeParseDefaultImportSpecifier(e)||this.eat(p.comma),r=t&&this.maybeParseStarImportSpecifier(e);t&&!r&&this.parseNamedImportSpecifiers(e),this.expectContextual("from")}e.source=this.parseImportSource();const t=this.maybeParseImportAssertions();if(t)e.assertions=t;else{const t=this.maybeParseModuleAttributes();t&&(e.attributes=t)}return this.semicolon(),this.finishNode(e,"ImportDeclaration")}parseImportSource(){return this.match(p.string)||this.unexpected(),this.parseExprAtom()}shouldParseDefaultImport(e){return this.match(p.name)}parseImportSpecifierLocal(e,t,r,n){t.local=this.parseIdentifier(),this.checkLVal(t.local,n,9),e.specifiers.push(this.finishNode(t,r))}parseAssertEntries(){const e=[],t=new Set;do{if(this.match(p.braceR))break;const r=this.startNode(),n=this.state.value;if(t.has(n)&&this.raise(this.state.start,x.ModuleAttributesWithDuplicateKeys,n),t.add(n),this.match(p.string)?r.key=this.parseStringLiteral(n):r.key=this.parseIdentifier(!0),this.expect(p.colon),!this.match(p.string))throw this.unexpected(this.state.start,x.ModuleAttributeInvalidValue);r.value=this.parseStringLiteral(this.state.value),this.finishNode(r,"ImportAttribute"),e.push(r)}while(this.eat(p.comma));return e}maybeParseModuleAttributes(){if(!this.match(p._with)||this.hasPrecedingLineBreak())return this.hasPlugin("moduleAttributes")?[]:null;this.expectPlugin("moduleAttributes"),this.next();const e=[],t=new Set;do{const r=this.startNode();if(r.key=this.parseIdentifier(!0),"type"!==r.key.name&&this.raise(r.key.start,x.ModuleAttributeDifferentFromType,r.key.name),t.has(r.key.name)&&this.raise(r.key.start,x.ModuleAttributesWithDuplicateKeys,r.key.name),t.add(r.key.name),this.expect(p.colon),!this.match(p.string))throw this.unexpected(this.state.start,x.ModuleAttributeInvalidValue);r.value=this.parseStringLiteral(this.state.value),this.finishNode(r,"ImportAttribute"),e.push(r)}while(this.eat(p.comma));return e}maybeParseImportAssertions(){if(!this.isContextual("assert")||this.hasPrecedingLineBreak())return this.hasPlugin("importAssertions")?[]:null;this.expectPlugin("importAssertions"),this.next(),this.eat(p.braceL);const e=this.parseAssertEntries();return this.eat(p.braceR),e}maybeParseDefaultImportSpecifier(e){return!!this.shouldParseDefaultImport(e)&&(this.parseImportSpecifierLocal(e,this.startNode(),"ImportDefaultSpecifier","default import specifier"),!0)}maybeParseStarImportSpecifier(e){if(this.match(p.star)){const t=this.startNode();return this.next(),this.expectContextual("as"),this.parseImportSpecifierLocal(e,t,"ImportNamespaceSpecifier","import namespace specifier"),!0}return!1}parseNamedImportSpecifiers(e){let t=!0;for(this.expect(p.braceL);!this.eat(p.braceR);){if(t)t=!1;else{if(this.eat(p.colon))throw this.raise(this.state.start,x.DestructureNamedImport);if(this.expect(p.comma),this.eat(p.braceR))break}this.parseImportSpecifier(e)}}parseImportSpecifier(e){const t=this.startNode(),r=this.match(p.string);if(t.imported=this.parseModuleExportName(),this.eatContextual("as"))t.local=this.parseIdentifier();else{const{imported:e}=t;if(r)throw this.raise(t.start,x.ImportBindingIsString,e.value);this.checkReservedWord(e.name,t.start,!0,!0),t.local=e.__clone()}this.checkLVal(t.local,"import specifier",9),e.specifiers.push(this.finishNode(t,"ImportSpecifier"))}isThisParam(e){return"Identifier"===e.type&&"this"===e.name}}{constructor(e,t){super(e=function(e){const t={};for(const r of Object.keys(Se))t[r]=e&&null!=e[r]?e[r]:Se[r];return t}(e),t),this.options=e,this.initializeScopes(),this.plugins=function(e){const t=new Map;for(const r of e){const[e,n]=Array.isArray(r)?r:[r,{}];t.has(e)||t.set(e,n||{})}return t}(this.options.plugins),this.filename=e.sourceFilename}getScopeHandler(){return K}parse(){this.enterInitialScopes();const e=this.startNode(),t=this.startNode();return this.nextToken(),e.errors=null,this.parseTopLevel(e,t),e.errors=this.state.errors,e}}function qe(e,t){let r=$e;return null!=e&&e.plugins&&(function(e){if(ye(e,"decorators")){if(ye(e,"decorators-legacy"))throw new Error("Cannot use the decorators and decorators-legacy plugin together");const t=ge(e,"decorators","decoratorsBeforeExport");if(null==t)throw new Error("The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you are migrating from Babylon/Babel 6 or want to use the old decorators proposal, you should use the 'decorators-legacy' plugin instead of 'decorators'.");if("boolean"!=typeof t)throw new Error("'decoratorsBeforeExport' must be a boolean.")}if(ye(e,"flow")&&ye(e,"typescript"))throw new Error("Cannot combine flow and typescript plugins.");if(ye(e,"placeholders")&&ye(e,"v8intrinsic"))throw new Error("Cannot combine placeholders and v8intrinsic plugins.");if(ye(e,"pipelineOperator")&&!be.includes(ge(e,"pipelineOperator","proposal")))throw new Error("'pipelineOperator' requires 'proposal' option whose value should be one of: "+be.map((e=>`'${e}'`)).join(", "));if(ye(e,"moduleAttributes")){if(ye(e,"importAssertions"))throw new Error("Cannot combine importAssertions and moduleAttributes plugins.");if("may-2020"!==ge(e,"moduleAttributes","version"))throw new Error("The 'moduleAttributes' plugin requires a 'version' option, representing the last proposal update. Currently, the only supported value is 'may-2020'.")}if(ye(e,"recordAndTuple")&&!ve.includes(ge(e,"recordAndTuple","syntaxType")))throw new Error("'recordAndTuple' requires 'syntaxType' option whose value should be one of: "+ve.map((e=>`'${e}'`)).join(", "));if(ye(e,"asyncDoExpressions")&&!ye(e,"doExpressions")){const e=new Error("'asyncDoExpressions' requires 'doExpressions', please add 'doExpressions' to parser plugins.");throw e.missingPlugins="doExpressions",e}}(e.plugins),r=function(e){const t=xe.filter((t=>ye(e,t))),r=t.join("/");let n=Ve[r];if(!n){n=$e;for(const e of t)n=Ee[e](n);Ve[r]=n}return n}(e.plugins)),new r(e,t)}const Ve={};t.parse=function(e,t){var r;if("unambiguous"!==(null==(r=t)?void 0:r.sourceType))return qe(t,e).parse();t=Object.assign({},t);try{t.sourceType="module";const r=qe(t,e),n=r.parse();if(r.sawUnambiguousESM)return n;if(r.ambiguousScriptDifferentAst)try{return t.sourceType="script",qe(t,e).parse()}catch(e){}else n.program.sourceType="script";return n}catch(r){try{return t.sourceType="script",qe(t,e).parse()}catch(e){}throw r}},t.parseExpression=function(e,t){const r=qe(t,e);return r.options.strictMode&&(r.state.strict=!0),r.getExpression()},t.tokTypes=p},(e,t,r)=>{const n=r(23);e.exports={re:n.re,src:n.src,tokens:n.t,SEMVER_SPEC_VERSION:r(41).SEMVER_SPEC_VERSION,SemVer:r(3),compareIdentifiers:r(94).compareIdentifiers,rcompareIdentifiers:r(94).rcompareIdentifiers,parse:r(29),valid:r(261),clean:r(262),inc:r(263),diff:r(264),major:r(265),minor:r(266),patch:r(267),prerelease:r(268),compare:r(12),rcompare:r(269),compareLoose:r(270),compareBuild:r(72),sort:r(271),rsort:r(272),gt:r(44),lt:r(73),eq:r(71),neq:r(147),gte:r(74),lte:r(75),cmp:r(148),coerce:r(273),Comparator:r(45),Range:r(13),satisfies:r(46),toComparators:r(276),maxSatisfying:r(277),minSatisfying:r(278),minVersion:r(279),validRange:r(280),outside:r(76),gtr:r(281),ltr:r(282),intersects:r(283),simplifyRange:r(284),subset:r(285)}},(e,t,r)=>{const{MAX_LENGTH:n}=r(41),{re:s,t:i}=r(23),o=r(3),a=r(43);e.exports=(e,t)=>{if(t=a(t),e instanceof o)return e;if("string"!=typeof e)return null;if(e.length>n)return null;if(!(t.loose?s[i.LOOSE]:s[i.FULL]).test(e))return null;try{return new o(e,t)}catch(e){return null}}},(e,t,r)=>{"use strict";var n=r(7);function s(e){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var i,o,a=r(240).codes,l=a.ERR_AMBIGUOUS_ARGUMENT,c=a.ERR_INVALID_ARG_TYPE,u=a.ERR_INVALID_ARG_VALUE,p=a.ERR_INVALID_RETURN_VALUE,f=a.ERR_MISSING_ARGS,d=r(249),h=r(36).inspect,m=r(36).types,y=m.isPromise,g=m.isRegExp,b=Object.assign?Object.assign:r(250).assign,v=Object.is?Object.is:r(140);function E(){var e=r(254);i=e.isDeepEqual,o=e.isDeepStrictEqual}new Map;var x=!1,S=e.exports=A,T={};function w(e){if(e.message instanceof Error)throw e.message;throw new d(e)}function P(e,t,r,n){if(!r){var s=!1;if(0===t)s=!0,n="No value argument passed to `assert.ok()`";else if(n instanceof Error)throw n;var i=new d({actual:r,expected:!0,message:n,operator:"==",stackStartFn:e});throw i.generatedMessage=s,i}}function A(){for(var e=arguments.length,t=new Array(e),r=0;r1?r-1:0),s=1;s1?r-1:0),s=1;s1?r-1:0),s=1;s1?r-1:0),s=1;s{var n=r(16);e.exports=!n((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},(e,t,r)=>{var n=r(31),s=r(112),i=r(116);e.exports=n?function(e,t,r){return s.f(e,t,i(1,r))}:function(e,t,r){return e[t]=r,e}},(e,t,r)=>{var n=r(59);e.exports=n("navigator","userAgent")||""},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.clear=function(){s(),i()},t.clearPath=s,t.clearScope=i,t.scope=t.path=void 0;let r=new WeakMap;t.path=r;let n=new WeakMap;function s(){t.path=r=new WeakMap}function i(){t.scope=n=new WeakMap}t.scope=n},(e,t,r)=>{"use strict";let n,s,i=r(22);class o extends i{constructor(e){super(e),this.type="root",this.nodes||(this.nodes=[])}removeChild(e,t){let r=this.index(e);return!t&&0===r&&this.nodes.length>1&&(this.nodes[1].raws.before=this.nodes[r].raws.before),super.removeChild(e)}normalize(e,t,r){let n=super.normalize(e);if(t)if("prepend"===r)this.nodes.length>1?t.raws.before=this.nodes[1].raws.before:delete t.raws.before;else if(this.first!==t)for(let e of n)e.raws.before=t.raws.before;return n}toResult(e={}){return new n(new s,this,e).stringify()}}o.registerLazyResult=e=>{n=e},o.registerProcessor=e=>{s=e},e.exports=o,o.default=o},(e,t,r)=>{var n=r(7),s=Object.getOwnPropertyDescriptors||function(e){for(var t=Object.keys(e),r={},n=0;n=s)return e;switch(e){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch(e){return"[Circular]"}default:return e}})),a=n[r];r=3&&(n.depth=arguments[2]),arguments.length>=4&&(n.colors=arguments[3]),m(r)?n.showHidden=r:r&&t._extend(n,r),v(n.showHidden)&&(n.showHidden=!1),v(n.depth)&&(n.depth=2),v(n.colors)&&(n.colors=!1),v(n.customInspect)&&(n.customInspect=!0),n.colors&&(n.stylize=c),p(n,e,n.depth)}function c(e,t){var r=l.styles[t];return r?"["+l.colors[r][0]+"m"+e+"["+l.colors[r][1]+"m":e}function u(e,t){return e}function p(e,r,n){if(e.customInspect&&r&&w(r.inspect)&&r.inspect!==t.inspect&&(!r.constructor||r.constructor.prototype!==r)){var s=r.inspect(n,e);return b(s)||(s=p(e,s,n)),s}var i=function(e,t){if(v(t))return e.stylize("undefined","undefined");if(b(t)){var r="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(r,"string")}return g(t)?e.stylize(""+t,"number"):m(t)?e.stylize(""+t,"boolean"):y(t)?e.stylize("null","null"):void 0}(e,r);if(i)return i;var o=Object.keys(r),a=function(e){var t={};return e.forEach((function(e,r){t[e]=!0})),t}(o);if(e.showHidden&&(o=Object.getOwnPropertyNames(r)),T(r)&&(o.indexOf("message")>=0||o.indexOf("description")>=0))return f(r);if(0===o.length){if(w(r)){var l=r.name?": "+r.name:"";return e.stylize("[Function"+l+"]","special")}if(E(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(S(r))return e.stylize(Date.prototype.toString.call(r),"date");if(T(r))return f(r)}var c,u="",x=!1,P=["{","}"];return h(r)&&(x=!0,P=["[","]"]),w(r)&&(u=" [Function"+(r.name?": "+r.name:"")+"]"),E(r)&&(u=" "+RegExp.prototype.toString.call(r)),S(r)&&(u=" "+Date.prototype.toUTCString.call(r)),T(r)&&(u=" "+f(r)),0!==o.length||x&&0!=r.length?n<0?E(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special"):(e.seen.push(r),c=x?function(e,t,r,n,s){for(var i=[],o=0,a=t.length;o60?r[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+r[1]:r[0]+t+" "+e.join(", ")+" "+r[1]}(c,u,P)):P[0]+u+P[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function d(e,t,r,n,s,i){var o,a,l;if((l=Object.getOwnPropertyDescriptor(t,s)||{value:t[s]}).get?a=l.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):l.set&&(a=e.stylize("[Setter]","special")),A(n,s)||(o="["+s+"]"),a||(e.seen.indexOf(l.value)<0?(a=y(r)?p(e,l.value,null):p(e,l.value,r-1)).indexOf("\n")>-1&&(a=i?a.split("\n").map((function(e){return" "+e})).join("\n").substr(2):"\n"+a.split("\n").map((function(e){return" "+e})).join("\n")):a=e.stylize("[Circular]","special")),v(o)){if(i&&s.match(/^\d+$/))return a;(o=JSON.stringify(""+s)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.substr(1,o.length-2),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+a}function h(e){return Array.isArray(e)}function m(e){return"boolean"==typeof e}function y(e){return null===e}function g(e){return"number"==typeof e}function b(e){return"string"==typeof e}function v(e){return void 0===e}function E(e){return x(e)&&"[object RegExp]"===P(e)}function x(e){return"object"==typeof e&&null!==e}function S(e){return x(e)&&"[object Date]"===P(e)}function T(e){return x(e)&&("[object Error]"===P(e)||e instanceof Error)}function w(e){return"function"==typeof e}function P(e){return Object.prototype.toString.call(e)}function A(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.debuglog=function(e){return e=e.toUpperCase(),o[e]||(a.test(e)?(n.pid,o[e]=function(){t.format.apply(t,arguments)}):o[e]=function(){}),o[e]},t.inspect=l,l.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},l.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.types=r(241),t.isArray=h,t.isBoolean=m,t.isNull=y,t.isNullOrUndefined=function(e){return null==e},t.isNumber=g,t.isString=b,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=v,t.isRegExp=E,t.types.isRegExp=E,t.isObject=x,t.isDate=S,t.types.isDate=S,t.isError=T,t.types.isNativeError=T,t.isFunction=w,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=r(248),t.log=function(){},t.inherits=r(171),t._extend=function(e,t){if(!t||!x(t))return e;for(var r=Object.keys(t),n=r.length;n--;)e[r[n]]=t[r[n]];return e};var O="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function C(e,t){if(!e){var r=new Error("Promise was rejected with a falsy value");r.reason=e,e=r}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(O&&e[O]){var t;if("function"!=typeof(t=e[O]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,O,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,r,n=new Promise((function(e,n){t=e,r=n})),s=[],i=0;i{"use strict"; /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */const n=r(427),s=r(428),i="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;t.Buffer=l,t.SlowBuffer=function(e){return+e!=e&&(e=0),l.alloc(+e)},t.INSPECT_MAX_BYTES=50;const o=2147483647;function a(e){if(e>o)throw new RangeError('The value "'+e+'" is invalid for option "size"');const t=new Uint8Array(e);return Object.setPrototypeOf(t,l.prototype),t}function l(e,t,r){if("number"==typeof e){if("string"==typeof t)throw new TypeError('The "string" argument must be of type string. Received type number');return p(e)}return c(e,t,r)}function c(e,t,r){if("string"==typeof e)return function(e,t){if("string"==typeof t&&""!==t||(t="utf8"),!l.isEncoding(t))throw new TypeError("Unknown encoding: "+t);const r=0|m(e,t);let n=a(r);const s=n.write(e,t);return s!==r&&(n=n.slice(0,s)),n}(e,t);if(ArrayBuffer.isView(e))return function(e){if(Y(e,Uint8Array)){const t=new Uint8Array(e);return d(t.buffer,t.byteOffset,t.byteLength)}return f(e)}(e);if(null==e)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(Y(e,ArrayBuffer)||e&&Y(e.buffer,ArrayBuffer))return d(e,t,r);if("undefined"!=typeof SharedArrayBuffer&&(Y(e,SharedArrayBuffer)||e&&Y(e.buffer,SharedArrayBuffer)))return d(e,t,r);if("number"==typeof e)throw new TypeError('The "value" argument must not be of type number. Received type number');const n=e.valueOf&&e.valueOf();if(null!=n&&n!==e)return l.from(n,t,r);const s=function(e){if(l.isBuffer(e)){const t=0|h(e.length),r=a(t);return 0===r.length||e.copy(r,0,0,t),r}return void 0!==e.length?"number"!=typeof e.length||X(e.length)?a(0):f(e):"Buffer"===e.type&&Array.isArray(e.data)?f(e.data):void 0}(e);if(s)return s;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return l.from(e[Symbol.toPrimitive]("string"),t,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function u(e){if("number"!=typeof e)throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function p(e){return u(e),a(e<0?0:0|h(e))}function f(e){const t=e.length<0?0:0|h(e.length),r=a(t);for(let n=0;n=o)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+o.toString(16)+" bytes");return 0|e}function m(e,t){if(l.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||Y(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);const r=e.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;let s=!1;for(;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return G(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return H(e).length;default:if(s)return n?-1:G(e).length;t=(""+t).toLowerCase(),s=!0}}function y(e,t,r){let n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return k(this,t,r);case"utf8":case"utf-8":return A(this,t,r);case"ascii":return C(this,t,r);case"latin1":case"binary":return I(this,t,r);case"base64":return P(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function g(e,t,r){const n=e[t];e[t]=e[r],e[r]=n}function b(e,t,r,n,s){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),X(r=+r)&&(r=s?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(s)return-1;r=e.length-1}else if(r<0){if(!s)return-1;r=0}if("string"==typeof t&&(t=l.from(t,n)),l.isBuffer(t))return 0===t.length?-1:v(e,t,r,n,s);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?s?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,n,s);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,n,s){let i,o=1,a=e.length,l=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;o=2,a/=2,l/=2,r/=2}function c(e,t){return 1===o?e[t]:e.readUInt16BE(t*o)}if(s){let n=-1;for(i=r;ia&&(r=a-l),i=r;i>=0;i--){let r=!0;for(let n=0;ns&&(n=s):n=s;const i=t.length;let o;for(n>i/2&&(n=i/2),o=0;o>8,s=r%256,i.push(s),i.push(n);return i}(t,e.length-r),e,r,n)}function P(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function A(e,t,r){r=Math.min(e.length,r);const n=[];let s=t;for(;s239?4:t>223?3:t>191?2:1;if(s+o<=r){let r,n,a,l;switch(o){case 1:t<128&&(i=t);break;case 2:r=e[s+1],128==(192&r)&&(l=(31&t)<<6|63&r,l>127&&(i=l));break;case 3:r=e[s+1],n=e[s+2],128==(192&r)&&128==(192&n)&&(l=(15&t)<<12|(63&r)<<6|63&n,l>2047&&(l<55296||l>57343)&&(i=l));break;case 4:r=e[s+1],n=e[s+2],a=e[s+3],128==(192&r)&&128==(192&n)&&128==(192&a)&&(l=(15&t)<<18|(63&r)<<12|(63&n)<<6|63&a,l>65535&&l<1114112&&(i=l))}}null===i?(i=65533,o=1):i>65535&&(i-=65536,n.push(i>>>10&1023|55296),i=56320|1023&i),n.push(i),s+=o}return function(e){const t=e.length;if(t<=O)return String.fromCharCode.apply(String,e);let r="",n=0;for(;nn.length?(l.isBuffer(t)||(t=l.from(t)),t.copy(n,s)):Uint8Array.prototype.set.call(n,t,s);else{if(!l.isBuffer(t))throw new TypeError('"list" argument must be an Array of Buffers');t.copy(n,s)}s+=t.length}return n},l.byteLength=m,l.prototype._isBuffer=!0,l.prototype.swap16=function(){const e=this.length;if(e%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let t=0;tr&&(e+=" ... "),""},i&&(l.prototype[i]=l.prototype.inspect),l.prototype.compare=function(e,t,r,n,s){if(Y(e,Uint8Array)&&(e=l.from(e,e.offset,e.byteLength)),!l.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===s&&(s=this.length),t<0||r>e.length||n<0||s>this.length)throw new RangeError("out of range index");if(n>=s&&t>=r)return 0;if(n>=s)return-1;if(t>=r)return 1;if(this===e)return 0;let i=(s>>>=0)-(n>>>=0),o=(r>>>=0)-(t>>>=0);const a=Math.min(i,o),c=this.slice(n,s),u=e.slice(t,r);for(let e=0;e>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}const s=this.length-t;if((void 0===r||r>s)&&(r=s),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");let i=!1;for(;;)switch(n){case"hex":return E(this,e,t,r);case"utf8":case"utf-8":return x(this,e,t,r);case"ascii":case"latin1":case"binary":return S(this,e,t,r);case"base64":return T(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return w(this,e,t,r);default:if(i)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),i=!0}},l.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const O=4096;function C(e,t,r){let n="";r=Math.min(e.length,r);for(let s=t;sn)&&(r=n);let s="";for(let n=t;nr)throw new RangeError("Trying to access beyond buffer length")}function j(e,t,r,n,s,i){if(!l.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>s||te.length)throw new RangeError("Index out of range")}function D(e,t,r,n,s){q(t,n,s,e,r,7);let i=Number(t&BigInt(4294967295));e[r++]=i,i>>=8,e[r++]=i,i>>=8,e[r++]=i,i>>=8,e[r++]=i;let o=Number(t>>BigInt(32)&BigInt(4294967295));return e[r++]=o,o>>=8,e[r++]=o,o>>=8,e[r++]=o,o>>=8,e[r++]=o,r}function L(e,t,r,n,s){q(t,n,s,e,r,7);let i=Number(t&BigInt(4294967295));e[r+7]=i,i>>=8,e[r+6]=i,i>>=8,e[r+5]=i,i>>=8,e[r+4]=i;let o=Number(t>>BigInt(32)&BigInt(4294967295));return e[r+3]=o,o>>=8,e[r+2]=o,o>>=8,e[r+1]=o,o>>=8,e[r]=o,r+8}function M(e,t,r,n,s,i){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function B(e,t,r,n,i){return t=+t,r>>>=0,i||M(e,0,r,4),s.write(e,t,r,n,23,4),r+4}function R(e,t,r,n,i){return t=+t,r>>>=0,i||M(e,0,r,8),s.write(e,t,r,n,52,8),r+8}l.prototype.slice=function(e,t){const r=this.length;(e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t>>=0,t>>>=0,r||_(e,t,this.length);let n=this[e],s=1,i=0;for(;++i>>=0,t>>>=0,r||_(e,t,this.length);let n=this[e+--t],s=1;for(;t>0&&(s*=256);)n+=this[e+--t]*s;return n},l.prototype.readUint8=l.prototype.readUInt8=function(e,t){return e>>>=0,t||_(e,1,this.length),this[e]},l.prototype.readUint16LE=l.prototype.readUInt16LE=function(e,t){return e>>>=0,t||_(e,2,this.length),this[e]|this[e+1]<<8},l.prototype.readUint16BE=l.prototype.readUInt16BE=function(e,t){return e>>>=0,t||_(e,2,this.length),this[e]<<8|this[e+1]},l.prototype.readUint32LE=l.prototype.readUInt32LE=function(e,t){return e>>>=0,t||_(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},l.prototype.readUint32BE=l.prototype.readUInt32BE=function(e,t){return e>>>=0,t||_(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},l.prototype.readBigUInt64LE=Q((function(e){V(e>>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||W(e,this.length-8);const n=t+256*this[++e]+65536*this[++e]+this[++e]*2**24,s=this[++e]+256*this[++e]+65536*this[++e]+r*2**24;return BigInt(n)+(BigInt(s)<>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||W(e,this.length-8);const n=t*2**24+65536*this[++e]+256*this[++e]+this[++e],s=this[++e]*2**24+65536*this[++e]+256*this[++e]+r;return(BigInt(n)<>>=0,t>>>=0,r||_(e,t,this.length);let n=this[e],s=1,i=0;for(;++i=s&&(n-=Math.pow(2,8*t)),n},l.prototype.readIntBE=function(e,t,r){e>>>=0,t>>>=0,r||_(e,t,this.length);let n=t,s=1,i=this[e+--n];for(;n>0&&(s*=256);)i+=this[e+--n]*s;return s*=128,i>=s&&(i-=Math.pow(2,8*t)),i},l.prototype.readInt8=function(e,t){return e>>>=0,t||_(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},l.prototype.readInt16LE=function(e,t){e>>>=0,t||_(e,2,this.length);const r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt16BE=function(e,t){e>>>=0,t||_(e,2,this.length);const r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt32LE=function(e,t){return e>>>=0,t||_(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},l.prototype.readInt32BE=function(e,t){return e>>>=0,t||_(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},l.prototype.readBigInt64LE=Q((function(e){V(e>>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||W(e,this.length-8);const n=this[e+4]+256*this[e+5]+65536*this[e+6]+(r<<24);return(BigInt(n)<>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||W(e,this.length-8);const n=(t<<24)+65536*this[++e]+256*this[++e]+this[++e];return(BigInt(n)<>>=0,t||_(e,4,this.length),s.read(this,e,!0,23,4)},l.prototype.readFloatBE=function(e,t){return e>>>=0,t||_(e,4,this.length),s.read(this,e,!1,23,4)},l.prototype.readDoubleLE=function(e,t){return e>>>=0,t||_(e,8,this.length),s.read(this,e,!0,52,8)},l.prototype.readDoubleBE=function(e,t){return e>>>=0,t||_(e,8,this.length),s.read(this,e,!1,52,8)},l.prototype.writeUintLE=l.prototype.writeUIntLE=function(e,t,r,n){e=+e,t>>>=0,r>>>=0,n||j(this,e,t,r,Math.pow(2,8*r)-1,0);let s=1,i=0;for(this[t]=255&e;++i>>=0,r>>>=0,n||j(this,e,t,r,Math.pow(2,8*r)-1,0);let s=r-1,i=1;for(this[t+s]=255&e;--s>=0&&(i*=256);)this[t+s]=e/i&255;return t+r},l.prototype.writeUint8=l.prototype.writeUInt8=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,1,255,0),this[t]=255&e,t+1},l.prototype.writeUint16LE=l.prototype.writeUInt16LE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},l.prototype.writeUint16BE=l.prototype.writeUInt16BE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},l.prototype.writeUint32LE=l.prototype.writeUInt32LE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},l.prototype.writeUint32BE=l.prototype.writeUInt32BE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},l.prototype.writeBigUInt64LE=Q((function(e,t=0){return D(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))})),l.prototype.writeBigUInt64BE=Q((function(e,t=0){return L(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))})),l.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t>>>=0,!n){const n=Math.pow(2,8*r-1);j(this,e,t,r,n-1,-n)}let s=0,i=1,o=0;for(this[t]=255&e;++s>0)-o&255;return t+r},l.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t>>>=0,!n){const n=Math.pow(2,8*r-1);j(this,e,t,r,n-1,-n)}let s=r-1,i=1,o=0;for(this[t+s]=255&e;--s>=0&&(i*=256);)e<0&&0===o&&0!==this[t+s+1]&&(o=1),this[t+s]=(e/i>>0)-o&255;return t+r},l.prototype.writeInt8=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},l.prototype.writeInt16LE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},l.prototype.writeInt16BE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},l.prototype.writeInt32LE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},l.prototype.writeInt32BE=function(e,t,r){return e=+e,t>>>=0,r||j(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},l.prototype.writeBigInt64LE=Q((function(e,t=0){return D(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),l.prototype.writeBigInt64BE=Q((function(e,t=0){return L(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),l.prototype.writeFloatLE=function(e,t,r){return B(this,e,t,!0,r)},l.prototype.writeFloatBE=function(e,t,r){return B(this,e,t,!1,r)},l.prototype.writeDoubleLE=function(e,t,r){return R(this,e,t,!0,r)},l.prototype.writeDoubleBE=function(e,t,r){return R(this,e,t,!1,r)},l.prototype.copy=function(e,t,r,n){if(!l.isBuffer(e))throw new TypeError("argument should be a Buffer");if(r||(r=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(s=t;s=n+4;r-=3)t=`_${e.slice(r-3,r)}${t}`;return`${e.slice(0,r)}${t}`}function q(e,t,r,n,s,i){if(e>r||e3?0===t||t===BigInt(0)?`>= 0${n} and < 2${n} ** ${8*(i+1)}${n}`:`>= -(2${n} ** ${8*(i+1)-1}${n}) and < 2 ** ${8*(i+1)-1}${n}`:`>= ${t}${n} and <= ${r}${n}`,new F.ERR_OUT_OF_RANGE("value",s,e)}!function(e,t,r){V(t,"offset"),void 0!==e[t]&&void 0!==e[t+r]||W(t,e.length-(r+1))}(n,s,i)}function V(e,t){if("number"!=typeof e)throw new F.ERR_INVALID_ARG_TYPE(t,"number",e)}function W(e,t,r){if(Math.floor(e)!==e)throw V(e,r),new F.ERR_OUT_OF_RANGE(r||"offset","an integer",e);if(t<0)throw new F.ERR_BUFFER_OUT_OF_BOUNDS;throw new F.ERR_OUT_OF_RANGE(r||"offset",`>= ${r?1:0} and <= ${t}`,e)}U("ERR_BUFFER_OUT_OF_BOUNDS",(function(e){return e?`${e} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"}),RangeError),U("ERR_INVALID_ARG_TYPE",(function(e,t){return`The "${e}" argument must be of type number. Received type ${typeof t}`}),TypeError),U("ERR_OUT_OF_RANGE",(function(e,t,r){let n=`The value of "${e}" is out of range.`,s=r;return Number.isInteger(r)&&Math.abs(r)>2**32?s=$(String(r)):"bigint"==typeof r&&(s=String(r),(r>BigInt(2)**BigInt(32)||r<-(BigInt(2)**BigInt(32)))&&(s=$(s)),s+="n"),n+=` It must be ${t}. Received ${s}`,n}),RangeError);const K=/[^+/0-9A-Za-z-_]/g;function G(e,t){let r;t=t||1/0;const n=e.length;let s=null;const i=[];for(let o=0;o55295&&r<57344){if(!s){if(r>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(o+1===n){(t-=3)>-1&&i.push(239,191,189);continue}s=r;continue}if(r<56320){(t-=3)>-1&&i.push(239,191,189),s=r;continue}r=65536+(s-55296<<10|r-56320)}else s&&(t-=3)>-1&&i.push(239,191,189);if(s=null,r<128){if((t-=1)<0)break;i.push(r)}else if(r<2048){if((t-=2)<0)break;i.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function H(e){return n.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(K,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function J(e,t,r,n){let s;for(s=0;s=t.length||s>=e.length);++s)t[s+r]=e[s];return s}function Y(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function X(e){return e!=e}const z=function(){const e="0123456789abcdef",t=new Array(256);for(let r=0;r<16;++r){const n=16*r;for(let s=0;s<16;++s)t[n+s]=e[r]+e[s]}return t}();function Q(e){return"undefined"==typeof BigInt?Z:e}function Z(){throw new Error("BigInt not supported")}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t=!0){return"string"==typeof e&&((!t||!(0,n.isKeyword)(e)&&!(0,n.isStrictReservedWord)(e,!0))&&(0,n.isIdentifierName)(e))};var n=r(63)},(e,t,r)=>{"use strict";var n=r(7);Object.defineProperty(t,"__esModule",{value:!0}),t.codeFrameColumns=a,t.default=function(e,t,r,s={}){if(!i){i=!0;const e="Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";n.emitWarning?n.emitWarning(e,"DeprecationWarning"):new Error(e).name="DeprecationWarning"}return a(e,{start:{column:r=Math.max(r,0),line:t}},s)};var s=r(438);let i=!1;const o=/\r\n|[\n\r\u2028\u2029]/;function a(e,t,r={}){const n=(r.highlightCode||r.forceColor)&&(0,s.shouldHighlight)(r),i=(0,s.getChalk)(r),a=function(e){return{gutter:e.grey,marker:e.red.bold,message:e.red.bold}}(i),l=(e,t)=>n?e(t):t,c=e.split(o),{start:u,end:p,markerLines:f}=function(e,t,r){const n=Object.assign({column:0,line:-1},e.start),s=Object.assign({},n,e.end),{linesAbove:i=2,linesBelow:o=3}=r||{},a=n.line,l=n.column,c=s.line,u=s.column;let p=Math.max(a-(i+1),0),f=Math.min(t.length,c+o);-1===a&&(p=0),-1===c&&(f=t.length);const d=c-a,h={};if(d)for(let e=0;e<=d;e++){const r=e+a;if(l)if(0===e){const e=t[r-1].length;h[r]=[l,e-l+1]}else if(e===d)h[r]=[0,u];else{const n=t[r-e].length;h[r]=[0,n]}else h[r]=!0}else h[a]=l===u?!l||[l,0]:[l,u-l];return{start:p,end:f,markerLines:h}}(t,c,r),d=t.start&&"number"==typeof t.start.column,h=String(p).length;let m=(n?(0,s.default)(e,r):e).split(o).slice(u,p).map(((e,t)=>{const n=u+1+t,s=` ${` ${n}`.slice(-h)} |`,i=f[n],o=!f[n+1];if(i){let t="";if(Array.isArray(i)){const n=e.slice(0,Math.max(i[0]-1,0)).replace(/[^\t]/g," "),c=i[1]||1;t=["\n ",l(a.gutter,s.replace(/\d/g," "))," ",n,l(a.marker,"^").repeat(c)].join(""),o&&r.message&&(t+=" "+l(a.message,r.message))}return[l(a.marker,">"),l(a.gutter,s),e.length>0?` ${e}`:"",t].join("")}return` ${l(a.gutter,s)}${e.length>0?` ${e}`:""}`})).join("\n");return r.message&&!d&&(m=`${" ".repeat(h+1)}${r.message}\n${m}`),n?i.reset(m):m}},(e,t,r)=>{"use strict";var n=r(251),s="function"==typeof Symbol&&"symbol"==typeof Symbol("foo"),i=Object.prototype.toString,o=Array.prototype.concat,a=Object.defineProperty,l=a&&function(){var e={};try{for(var t in a(e,"x",{enumerable:!1,value:e}),e)return!1;return e.x===e}catch(e){return!1}}(),c=function(e,t,r,n){var s;(!(t in e)||"function"==typeof(s=n)&&"[object Function]"===i.call(s)&&n())&&(l?a(e,t,{configurable:!0,enumerable:!1,value:r,writable:!0}):e[t]=r)},u=function(e,t){var r=arguments.length>2?arguments[2]:{},i=n(t);s&&(i=o.call(i,Object.getOwnPropertySymbols(t)));for(var a=0;a{const t=Number.MAX_SAFE_INTEGER||9007199254740991;e.exports={SEMVER_SPEC_VERSION:"2.0.0",MAX_LENGTH:256,MAX_SAFE_INTEGER:t,MAX_SAFE_COMPONENT_LENGTH:16}},(e,t,r)=>{var n=r(7);const s=("object"==typeof n&&n.env,()=>{});e.exports=s},e=>{const t=["includePrerelease","loose","rtl"];e.exports=e=>e?"object"!=typeof e?{loose:!0}:t.filter((t=>e[t])).reduce(((e,t)=>(e[t]=!0,e)),{}):{}},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>n(e,t,r)>0},(e,t,r)=>{const n=Symbol("SemVer ANY");class s{static get ANY(){return n}constructor(e,t){if(t=i(t),e instanceof s){if(e.loose===!!t.loose)return e;e=e.value}c("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===n?this.value="":this.value=this.operator+this.semver.version,c("comp",this)}parse(e){const t=this.options.loose?o[a.COMPARATORLOOSE]:o[a.COMPARATOR],r=e.match(t);if(!r)throw new TypeError(`Invalid comparator: ${e}`);this.operator=void 0!==r[1]?r[1]:"","="===this.operator&&(this.operator=""),r[2]?this.semver=new u(r[2],this.options.loose):this.semver=n}toString(){return this.value}test(e){if(c("Comparator.test",e,this.options.loose),this.semver===n||e===n)return!0;if("string"==typeof e)try{e=new u(e,this.options)}catch(e){return!1}return l(e,this.operator,this.semver,this.options)}intersects(e,t){if(!(e instanceof s))throw new TypeError("a Comparator is required");if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return""===this.value||new p(e.value,t).test(this.value);if(""===e.operator)return""===e.value||new p(this.value,t).test(e.semver);const r=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),n=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),i=this.semver.version===e.semver.version,o=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=l(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=l(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return r||n||i&&o||a||c}}e.exports=s;const i=r(43),{re:o,t:a}=r(23),l=r(148),c=r(42),u=r(3),p=r(13)},(e,t,r)=>{const n=r(13);e.exports=(e,t,r)=>{try{t=new n(t,r)}catch(e){return!1}return t.test(e)}},(e,t,r)=>{"use strict";let n=r(48);class s extends n{constructor(e){e&&void 0!==e.value&&"string"!=typeof e.value&&(e={...e,value:String(e.value)}),super(e),this.type="decl"}get variable(){return this.prop.startsWith("--")||"$"===this.prop[0]}}e.exports=s,s.default=s},(e,t,r)=>{"use strict";let{isClean:n,my:s}=r(154),i=r(85),o=r(155),a=r(86);function l(e,t){let r=new e.constructor;for(let n in e){if(!Object.prototype.hasOwnProperty.call(e,n))continue;if("proxyCache"===n)continue;let s=e[n],i=typeof s;"parent"===n&&"object"===i?t&&(r[n]=t):"source"===n?r[n]=s:Array.isArray(s)?r[n]=s.map((e=>l(e,r))):("object"===i&&null!==s&&(s=l(s)),r[n]=s)}return r}class c{constructor(e={}){this.raws={},this[n]=!1,this[s]=!0;for(let t in e)if("nodes"===t){this.nodes=[];for(let r of e[t])"function"==typeof r.clone?this.append(r.clone()):this.append(r)}else this[t]=e[t]}error(e,t={}){if(this.source){let r=this.positionBy(t);return this.source.input.error(e,r.line,r.column,t)}return new i(e)}warn(e,t,r){let n={node:this};for(let e in r)n[e]=r[e];return e.warn(t,n)}remove(){return this.parent&&this.parent.removeChild(this),this.parent=void 0,this}toString(e=a){e.stringify&&(e=e.stringify);let t="";return e(this,(e=>{t+=e})),t}assign(e={}){for(let t in e)this[t]=e[t];return this}clone(e={}){let t=l(this);for(let r in e)t[r]=e[r];return t}cloneBefore(e={}){let t=this.clone(e);return this.parent.insertBefore(this,t),t}cloneAfter(e={}){let t=this.clone(e);return this.parent.insertAfter(this,t),t}replaceWith(...e){if(this.parent){let t=this,r=!1;for(let n of e)n===this?r=!0:r?(this.parent.insertAfter(t,n),t=n):this.parent.insertBefore(t,n);r||this.remove()}return this}next(){if(!this.parent)return;let e=this.parent.index(this);return this.parent.nodes[e+1]}prev(){if(!this.parent)return;let e=this.parent.index(this);return this.parent.nodes[e-1]}before(e){return this.parent.insertBefore(this,e),this}after(e){return this.parent.insertAfter(this,e),this}root(){let e=this;for(;e.parent&&"document"!==e.parent.type;)e=e.parent;return e}raw(e,t){return(new o).raw(this,e,t)}cleanRaws(e){delete this.raws.before,delete this.raws.after,e||delete this.raws.between}toJSON(e,t){let r={},n=null==t;t=t||new Map;let s=0;for(let e in this){if(!Object.prototype.hasOwnProperty.call(this,e))continue;if("parent"===e||"proxyCache"===e)continue;let n=this[e];if(Array.isArray(n))r[e]=n.map((e=>"object"==typeof e&&e.toJSON?e.toJSON(null,t):e));else if("object"==typeof n&&n.toJSON)r[e]=n.toJSON(null,t);else if("source"===e){let i=t.get(n.input);null==i&&(i=s,t.set(n.input,s),s++),r[e]={inputId:i,start:n.start,end:n.end}}else r[e]=n}return n&&(r.inputs=[...t.keys()].map((e=>e.toJSON()))),r}positionInside(e){let t=this.toString(),r=this.source.start.column,n=this.source.start.line;for(let s=0;s(e[t]===r||(e[t]=r,"prop"!==t&&"value"!==t&&"name"!==t&&"params"!==t&&"important"!==t&&"text"!==t||e.markDirty()),!0),get:(e,t)=>"proxyOf"===t?e:"root"===t?()=>e.root().toProxy():e[t]}}toProxy(){return this.proxyCache||(this.proxyCache=new Proxy(this,this.getProxyProcessor())),this.proxyCache}addToError(e){if(e.postcssNode=this,e.stack&&this.source&&/\n\s{4}at /.test(e.stack)){let t=this.source;e.stack=e.stack.replace(/\n\s{4}at /,`$&${t.input.from}:${t.start.line}:${t.start.column}$&`)}return e}markDirty(){if(this[n]){this[n]=!1;let e=this;for(;e=e.parent;)e[n]=!1}}get proxyOf(){return this}}e.exports=c,c.default=c},(e,t,r)=>{"use strict";let n=r(48);class s extends n{constructor(e){super(e),this.type="comment"}}e.exports=s,s.default=s},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.transformJSXSpreadAttribute=t.isConstant=t.dedupeProperties=t.isOn=t.buildIIFE=t.walksScope=t.transformJSXSpreadChild=t.transformJSXExpressionContainer=t.transformJSXText=t.getJSXAttributeName=t.getTag=t.transformJSXMemberExpression=t.checkIsComponent=t.shouldTransformedToSlots=t.isDirective=t.createIdentifier=t.KEEP_ALIVE=t.FRAGMENT=t.JSX_HELPER_KEY=void 0;const a=i(r(0)),l=o(r(532)),c=o(r(534));t.JSX_HELPER_KEY="JSX_HELPER_KEY",t.FRAGMENT="Fragment",t.KEEP_ALIVE="KeepAlive",t.createIdentifier=(e,t)=>e.get(t)(),t.isDirective=e=>e.startsWith("v-")||e.startsWith("v")&&e.length>=2&&e[1]>="A"&&e[1]<="Z",t.shouldTransformedToSlots=e=>!(e.endsWith(t.FRAGMENT)||e===t.KEEP_ALIVE),t.checkIsComponent=e=>{const r=e.get("name");if(r.isJSXMemberExpression())return t.shouldTransformedToSlots(r.node.property.name);const n=r.node.name;return t.shouldTransformedToSlots(n)&&!l.default.includes(n)&&!c.default.includes(n)},t.transformJSXMemberExpression=e=>{const r=e.node.object,n=e.node.property,s=a.isJSXMemberExpression(r)?t.transformJSXMemberExpression(e.get("object")):a.isJSXIdentifier(r)?a.identifier(r.name):a.nullLiteral(),i=a.identifier(n.name);return a.memberExpression(s,i)},t.getTag=(e,r)=>{var n,s;const i=e.get("openingElement").get("name");if(i.isJSXIdentifier()){const{name:o}=i.node;return l.default.includes(o)||c.default.includes(o)?a.stringLiteral(o):o===t.FRAGMENT?t.createIdentifier(r,t.FRAGMENT):e.scope.hasBinding(o)?a.identifier(o):(null===(s=(n=r.opts).isCustomElement)||void 0===s?void 0:s.call(n,o))?a.stringLiteral(o):a.callExpression(t.createIdentifier(r,"resolveComponent"),[a.stringLiteral(o)])}if(i.isJSXMemberExpression())return t.transformJSXMemberExpression(i);throw new Error(`getTag: ${i.type} is not supported`)},t.getJSXAttributeName=e=>{const t=e.node.name;return a.isJSXIdentifier(t)?t.name:`${t.namespace.name}:${t.name.name}`},t.transformJSXText=e=>{const{node:t}=e,r=t.value.split(/\r\n|\n|\r/);let n=0;for(let e=0;ee.get("expression").node,t.transformJSXSpreadChild=e=>a.spreadElement(e.get("expression").node),t.walksScope=(e,r,n)=>{e.scope.hasBinding(r)&&e.parentPath&&(a.isJSXElement(e.parentPath.node)&&e.parentPath.setData("slotFlag",n),t.walksScope(e.parentPath,r,n))},t.buildIIFE=(e,t)=>{const{parentPath:r}=e;if(a.isAssignmentExpression(r)){const{left:n}=r.node;if(a.isIdentifier(n))return t.map((t=>{if(a.isIdentifier(t)&&t.name===n.name){const n=e.scope.generateUidIdentifier(t.name);return r.insertBefore(a.variableDeclaration("const",[a.variableDeclarator(n,a.callExpression(a.functionExpression(null,[],a.blockStatement([a.returnStatement(t)])),[]))])),n}return t}))}return t};const u=/^on[^a-z]/;t.isOn=e=>u.test(e),t.dedupeProperties=(e=[],t)=>{if(!t)return e;const r=new Map,n=[];return e.forEach((e=>{if(a.isStringLiteral(e.key)){const{value:t}=e.key,s=r.get(t);s?("style"===t||"class"===t||t.startsWith("on"))&&((e,t)=>{a.isArrayExpression(e.value)?e.value.elements.push(t.value):e.value=a.arrayExpression([e.value,t.value])})(s,e):(r.set(t,e),n.push(e))}else n.push(e)})),n},t.isConstant=e=>{if(a.isIdentifier(e))return"undefined"===e.name;if(a.isArrayExpression(e)){const{elements:r}=e;return r.every((e=>e&&t.isConstant(e)))}return a.isObjectExpression(e)?e.properties.every((e=>t.isConstant(e.value))):!!a.isLiteral(e)},t.transformJSXSpreadAttribute=(e,r,n,s)=>{const i=r.get("argument"),o=a.isObjectExpression(i.node)?i.node.properties:void 0;o?n?s.push(a.objectExpression(o)):s.push(...o):(i.isIdentifier()&&t.walksScope(e,i.node.name,2),s.push(n?i.node:a.spreadElement(i.node)))}},(e,t,r)=>{"use strict";var n=r(69),s=r(67),i=s("%Function.prototype.apply%"),o=s("%Function.prototype.call%"),a=s("%Reflect.apply%",!0)||n.call(o,i),l=s("%Object.getOwnPropertyDescriptor%",!0),c=s("%Object.defineProperty%",!0),u=s("%Math.max%");if(c)try{c({},"a",{value:1})}catch(e){c=null}e.exports=function(e){var t=a(n,o,arguments);if(l&&c){var r=l(t,"length");r.configurable&&c(t,"length",{value:1+u(0,e.length-(arguments.length-1))})}return t};var p=function(){return a(n,i,arguments)};c?c(e.exports,"apply",{value:p}):e.exports.apply=p},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if(Object.prototype.hasOwnProperty.call(e,s)){var i=n?Object.getOwnPropertyDescriptor(e,s):null;i&&(i.get||i.set)?Object.defineProperty(r,s,i):r[s]=e[s]}return r.default=e,t&&t.set(e,r),r}(r(5));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r=e&&(this.indexes[r]=t-1);return this},u.removeAll=function(){for(var e,t=function(e,t){var r;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(r=function(e,t){if(e){if("string"==typeof e)return a(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?a(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(r=e[Symbol.iterator]()).next.bind(r)}(this.nodes);!(e=t()).done;)e.value.parent=void 0;return this.nodes=[],this},u.empty=function(){return this.removeAll()},u.insertAfter=function(e,t){t.parent=this;var r,n=this.index(e);for(var s in this.nodes.splice(n+1,0,t),t.parent=this,this.indexes)n<=(r=this.indexes[s])&&(this.indexes[s]=r+1);return this},u.insertBefore=function(e,t){t.parent=this;var r,n=this.index(e);for(var s in this.nodes.splice(n,0,t),t.parent=this,this.indexes)(r=this.indexes[s])<=n&&(this.indexes[s]=r+1);return this},u._findChildAtPosition=function(e,t){var r=void 0;return this.each((function(n){if(n.atPosition){var s=n.atPosition(e,t);if(s)return r=s,!1}else if(n.isAtPosition(e,t))return r=n,!1})),r},u.atPosition=function(e,t){return this.isAtPosition(e,t)?this._findChildAtPosition(e,t)||this:void 0},u._inferEndPosition=function(){this.last&&this.last.source&&this.last.source.end&&(this.source=this.source||{},this.source.end=this.source.end||{},Object.assign(this.source.end,this.last.source.end))},u.each=function(e){this.lastEach||(this.lastEach=0),this.indexes||(this.indexes={}),this.lastEach++;var t=this.lastEach;if(this.indexes[t]=0,this.length){for(var r,n;this.indexes[t]{"use strict";t.__esModule=!0,t.default=void 0;var n=i(r(92)),s=r(91);function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){for(var r=0;r{var n=r(2),s=r(111),i=r(17),o=r(58),a=r(117),l=r(185),c=s("wks"),u=n.Symbol,p=l?u:u&&u.withoutSetter||o;e.exports=function(e){return i(c,e)&&(a||"string"==typeof c[e])||(a&&i(u,e)?c[e]=u[e]:c[e]=p("Symbol."+e)),c[e]}},(e,t,r)=>{var n=r(2),s=r(56),i="__core-js_shared__",o=n[i]||s(i,{});e.exports=o},(e,t,r)=>{var n=r(2),s=r(32);e.exports=function(e,t){try{s(n,e,t)}catch(r){n[e]=t}return t}},(e,t,r)=>{var n=r(24);e.exports=function(e){if(!n(e))throw TypeError(String(e)+" is not an object");return e}},e=>{var t=0,r=Math.random();e.exports=function(e){return"Symbol("+String(void 0===e?"":e)+")_"+(++t+r).toString(36)}},(e,t,r)=>{var n=r(184),s=r(2),i=function(e){return"function"==typeof e?e:void 0};e.exports=function(e,t){return arguments.length<2?i(n[e])||i(s[e]):n[e]&&n[e][t]||s[e]&&s[e][t]}},e=>{var t={}.toString;e.exports=function(e){return t.call(e).slice(8,-1)}},(e,t,r)=>{var n=r(198),s=r(110);e.exports=function(e){return n(s(e))}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){return!!t&&((0,s.default)(t.type,e)?void 0===r||(0,n.default)(t,r):!r&&"Placeholder"===t.type&&e in o.FLIPPED_ALIAS_KEYS&&(0,i.default)(t.expectedNode,e))};var n=r(127),s=r(129),i=r(216),o=r(11)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"isIdentifierName",{enumerable:!0,get:function(){return n.isIdentifierName}}),Object.defineProperty(t,"isIdentifierChar",{enumerable:!0,get:function(){return n.isIdentifierChar}}),Object.defineProperty(t,"isIdentifierStart",{enumerable:!0,get:function(){return n.isIdentifierStart}}),Object.defineProperty(t,"isReservedWord",{enumerable:!0,get:function(){return s.isReservedWord}}),Object.defineProperty(t,"isStrictBindOnlyReservedWord",{enumerable:!0,get:function(){return s.isStrictBindOnlyReservedWord}}),Object.defineProperty(t,"isStrictBindReservedWord",{enumerable:!0,get:function(){return s.isStrictBindReservedWord}}),Object.defineProperty(t,"isStrictReservedWord",{enumerable:!0,get:function(){return s.isStrictReservedWord}}),Object.defineProperty(t,"isKeyword",{enumerable:!0,get:function(){return s.isKeyword}});var n=r(368),s=r(369)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=s;var n=r(1);function s(e,t,r){let i=[].concat(e);const o=Object.create(null);for(;i.length;){const e=i.shift();if(!e)continue;const a=s.keys[e.type];if((0,n.isIdentifier)(e))t?(o[e.name]=o[e.name]||[]).push(e):o[e.name]=e;else if(!(0,n.isExportDeclaration)(e)||(0,n.isExportAllDeclaration)(e)){if(r){if((0,n.isFunctionDeclaration)(e)){i.push(e.id);continue}if((0,n.isFunctionExpression)(e))continue}if(a)for(let t=0;t{e.exports=function(){return function(){}}},(e,t,r)=>{"use strict";var n=r(67),s=r(51),i=s(n("String.prototype.indexOf"));e.exports=function(e,t){var r=n(e,!!t);return"function"==typeof r&&i(e,".prototype.")>-1?s(r):r}},(e,t,r)=>{"use strict";var n,s=SyntaxError,i=Function,o=TypeError,a=function(e){try{return i('"use strict"; return ('+e+").constructor;")()}catch(e){}},l=Object.getOwnPropertyDescriptor;if(l)try{l({},"")}catch(e){l=null}var c=function(){throw new o},u=l?function(){try{return c}catch(e){try{return l(arguments,"callee").get}catch(e){return c}}}():c,p=r(68)(),f=Object.getPrototypeOf||function(e){return e.__proto__},d={},h="undefined"==typeof Uint8Array?n:f(Uint8Array),m={"%AggregateError%":"undefined"==typeof AggregateError?n:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?n:ArrayBuffer,"%ArrayIteratorPrototype%":p?f([][Symbol.iterator]()):n,"%AsyncFromSyncIteratorPrototype%":n,"%AsyncFunction%":d,"%AsyncGenerator%":d,"%AsyncGeneratorFunction%":d,"%AsyncIteratorPrototype%":d,"%Atomics%":"undefined"==typeof Atomics?n:Atomics,"%BigInt%":"undefined"==typeof BigInt?n:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?n:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?n:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?n:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?n:FinalizationRegistry,"%Function%":i,"%GeneratorFunction%":d,"%Int8Array%":"undefined"==typeof Int8Array?n:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?n:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?n:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":p?f(f([][Symbol.iterator]())):n,"%JSON%":"object"==typeof JSON?JSON:n,"%Map%":"undefined"==typeof Map?n:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&p?f((new Map)[Symbol.iterator]()):n,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?n:Promise,"%Proxy%":"undefined"==typeof Proxy?n:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?n:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?n:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&p?f((new Set)[Symbol.iterator]()):n,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?n:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":p?f(""[Symbol.iterator]()):n,"%Symbol%":p?Symbol:n,"%SyntaxError%":s,"%ThrowTypeError%":u,"%TypedArray%":h,"%TypeError%":o,"%Uint8Array%":"undefined"==typeof Uint8Array?n:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?n:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?n:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?n:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?n:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?n:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?n:WeakSet},y=function e(t){var r;if("%AsyncFunction%"===t)r=a("async function () {}");else if("%GeneratorFunction%"===t)r=a("function* () {}");else if("%AsyncGeneratorFunction%"===t)r=a("async function* () {}");else if("%AsyncGenerator%"===t){var n=e("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if("%AsyncIteratorPrototype%"===t){var s=e("%AsyncGenerator%");s&&(r=f(s.prototype))}return m[t]=r,r},g={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},b=r(69),v=r(245),E=b.call(Function.call,Array.prototype.concat),x=b.call(Function.apply,Array.prototype.splice),S=b.call(Function.call,String.prototype.replace),T=b.call(Function.call,String.prototype.slice),w=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,P=/\\(\\)?/g,A=function(e){var t=T(e,0,1),r=T(e,-1);if("%"===t&&"%"!==r)throw new s("invalid intrinsic syntax, expected closing `%`");if("%"===r&&"%"!==t)throw new s("invalid intrinsic syntax, expected opening `%`");var n=[];return S(e,w,(function(e,t,r,s){n[n.length]=r?S(s,P,"$1"):t||e})),n},O=function(e,t){var r,n=e;if(v(g,n)&&(n="%"+(r=g[n])[0]+"%"),v(m,n)){var i=m[n];if(i===d&&(i=y(n)),void 0===i&&!t)throw new o("intrinsic "+e+" exists, but is not available. Please file an issue!");return{alias:r,name:n,value:i}}throw new s("intrinsic "+e+" does not exist!")};e.exports=function(e,t){if("string"!=typeof e||0===e.length)throw new o("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof t)throw new o('"allowMissing" argument must be a boolean');var r=A(e),n=r.length>0?r[0]:"",i=O("%"+n+"%",t),a=i.name,c=i.value,u=!1,p=i.alias;p&&(n=p[0],x(r,E([0,1],p)));for(var f=1,d=!0;f=r.length){var b=l(c,h);c=(d=!!b)&&"get"in b&&!("originalValue"in b.get)?b.get:c[h]}else d=v(c,h),c=c[h];d&&!u&&(m[a]=c)}}return c}},(e,t,r)=>{"use strict";var n="undefined"!=typeof Symbol&&Symbol,s=r(243);e.exports=function(){return"function"==typeof n&&"function"==typeof Symbol&&"symbol"==typeof n("foo")&&"symbol"==typeof Symbol("bar")&&s()}},(e,t,r)=>{"use strict";var n=r(244);e.exports=Function.prototype.bind||n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.skipAllButComputedKey=l,t.default=t.environmentVisitor=void 0;var n=r(10),s=r(258),i=r(259),o=r(0);function a(e,t,r,n){e=o.cloneNode(e);const s=t||n?e:o.memberExpression(e,o.identifier("prototype"));return o.callExpression(r.addHelper("getPrototypeOf"),[s])}function l(e){if(!e.node.computed)return void e.skip();const t=o.VISITOR_KEYS[e.type];for(const r of t)"key"!==r&&e.skipKey(r)}const c={[(o.staticBlock?"StaticBlock|":"")+"ClassPrivateProperty|TypeAnnotation"](e){e.skip()},Function(e){e.isMethod()||e.isArrowFunctionExpression()||e.skip()},"Method|ClassProperty"(e){l(e)}};t.environmentVisitor=c;const u=n.default.visitors.merge([c,{Super(e,t){const{node:r,parentPath:n}=e;n.isMemberExpression({object:r})&&t.handle(n)}}]),p=n.default.visitors.merge([c,{Scopable(e,{refName:t}){const r=e.scope.getOwnBinding(t);r&&r.identifier.name===t&&e.scope.rename(t)}}]),f={memoise(e,t){const{scope:r,node:n}=e,{computed:s,property:i}=n;if(!s)return;const o=r.maybeGenerateMemoised(i);o&&this.memoiser.set(i,o,t)},prop(e){const{computed:t,property:r}=e.node;return this.memoiser.has(r)?o.cloneNode(this.memoiser.get(r)):t?o.cloneNode(r):o.stringLiteral(r.name)},get(e){return this._get(e,this._getThisRefs())},_get(e,t){const r=a(this.getObjectRef(),this.isStatic,this.file,this.isPrivateMethod);return o.callExpression(this.file.addHelper("get"),[t.memo?o.sequenceExpression([t.memo,r]):r,this.prop(e),t.this])},_getThisRefs(){if(!this.isDerivedConstructor)return{this:o.thisExpression()};const e=this.scope.generateDeclaredUidIdentifier("thisSuper");return{memo:o.assignmentExpression("=",e,o.thisExpression()),this:o.cloneNode(e)}},set(e,t){const r=this._getThisRefs(),n=a(this.getObjectRef(),this.isStatic,this.file,this.isPrivateMethod);return o.callExpression(this.file.addHelper("set"),[r.memo?o.sequenceExpression([r.memo,n]):n,this.prop(e),t,r.this,o.booleanLiteral(e.isInStrictMode())])},destructureSet(e){throw e.buildCodeFrameError("Destructuring to a super field is not supported yet.")},call(e,t){const r=this._getThisRefs();return(0,i.default)(this._get(e,r),o.cloneNode(r.this),t,!1)},optionalCall(e,t){const r=this._getThisRefs();return(0,i.default)(this._get(e,r),o.cloneNode(r.this),t,!0)}},d=Object.assign({},f,{prop(e){const{property:t}=e.node;return this.memoiser.has(t)?o.cloneNode(this.memoiser.get(t)):o.cloneNode(t)},get(e){const{isStatic:t,getSuperRef:r}=this,{computed:n}=e.node,s=this.prop(e);let i;var a,l;return i=t?null!=(a=r())?a:o.memberExpression(o.identifier("Function"),o.identifier("prototype")):o.memberExpression(null!=(l=r())?l:o.identifier("Object"),o.identifier("prototype")),o.memberExpression(i,s,n)},set(e,t){const{computed:r}=e.node,n=this.prop(e);return o.assignmentExpression("=",o.memberExpression(o.thisExpression(),n,r),t)},destructureSet(e){const{computed:t}=e.node,r=this.prop(e);return o.memberExpression(o.thisExpression(),r,t)},call(e,t){return(0,i.default)(this.get(e),o.thisExpression(),t,!1)},optionalCall(e,t){return(0,i.default)(this.get(e),o.thisExpression(),t,!0)}});t.default=class{constructor(e){var t;const r=e.methodPath;this.methodPath=r,this.isDerivedConstructor=r.isClassMethod({kind:"constructor"})&&!!e.superRef,this.isStatic=r.isObjectMethod()||r.node.static||(null==r.isStaticBlock?void 0:r.isStaticBlock()),this.isPrivateMethod=r.isPrivate()&&r.isMethod(),this.file=e.file,this.constantSuper=null!=(t=e.constantSuper)?t:e.isLoose,this.opts=e}getObjectRef(){return o.cloneNode(this.opts.objectRef||this.opts.getObjectRef())}getSuperRef(){return this.opts.superRef?o.cloneNode(this.opts.superRef):this.opts.getSuperRef?o.cloneNode(this.opts.getSuperRef()):void 0}replace(){this.opts.refToPreserve&&this.methodPath.traverse(p,{refName:this.opts.refToPreserve.name});const e=this.constantSuper?d:f;(0,s.default)(this.methodPath,u,Object.assign({file:this.file,scope:this.methodPath.scope,isDerivedConstructor:this.isDerivedConstructor,isStatic:this.isStatic,isPrivateMethod:this.isPrivateMethod,getObjectRef:this.getObjectRef.bind(this),getSuperRef:this.getSuperRef.bind(this)},e))}}},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>0===n(e,t,r)},(e,t,r)=>{const n=r(3);e.exports=(e,t,r)=>{const s=new n(e,r),i=new n(t,r);return s.compare(i)||s.compareBuild(i)}},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>n(e,t,r)<0},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>n(e,t,r)>=0},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>n(e,t,r)<=0},(e,t,r)=>{const n=r(3),s=r(45),{ANY:i}=s,o=r(13),a=r(46),l=r(44),c=r(73),u=r(75),p=r(74);e.exports=(e,t,r,f)=>{let d,h,m,y,g;switch(e=new n(e,f),t=new o(t,f),r){case">":d=l,h=u,m=c,y=">",g=">=";break;case"<":d=c,h=p,m=l,y="<",g="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(a(e,t,f))return!1;for(let r=0;r{e.semver===i&&(e=new s(">=0.0.0")),o=o||e,a=a||e,d(e.semver,o.semver,f)?o=e:m(e.semver,a.semver,f)&&(a=e)})),o.operator===y||o.operator===g)return!1;if((!a.operator||a.operator===y)&&h(e,a.semver))return!1;if(a.operator===g&&m(e,a.semver))return!1}return!0}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.findConfigUpwards=function(e){return null},t.findPackageData=function*(e){return{filepath:e,directories:[],pkg:null,isPackage:!1}},t.findRelativeConfig=function*(e,t,r){return{config:null,ignore:null}},t.findRootConfig=function*(e,t,r){return null},t.loadConfig=function*(e,t,r,n){throw new Error(`Cannot load ${e} relative to ${t} in a browser`)},t.resolveShowConfigPath=function*(e){return null},t.resolvePlugin=function(e,t){return null},t.resolvePreset=function(e,t){return null},t.loadPlugin=function(e,t){throw new Error(`Cannot load plugin ${e} relative to ${t} in a browser`)},t.loadPreset=function(e,t){throw new Error(`Cannot load preset ${e} relative to ${t} in a browser`)},t.ROOT_CONFIG_FILENAMES=void 0,t.ROOT_CONFIG_FILENAMES=[]},(e,t,r)=>{"use strict";function n(){const e=r(14);return n=function(){return e},e}Object.defineProperty(t,"__esModule",{value:!0}),t.createConfigItem=function(e,t,r){return void 0!==r?l.errback(e,t,r):"function"==typeof t?l.errback(e,void 0,r):l.sync(e,t)},Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s.default}}),t.createConfigItemAsync=t.createConfigItemSync=t.loadOptionsAsync=t.loadOptionsSync=t.loadOptions=t.loadPartialConfigAsync=t.loadPartialConfigSync=t.loadPartialConfig=void 0;var s=r(466),i=r(303),o=r(80);const a=n()((function*(e){var t;const r=yield*(0,s.default)(e);return null!=(t=null==r?void 0:r.options)?t:null})),l=n()(o.createConfigItem),c=e=>(t,r)=>(void 0===r&&"function"==typeof t&&(r=t,t=void 0),r?e.errback(t,r):e.sync(t)),u=c(i.loadPartialConfig);t.loadPartialConfig=u;const p=i.loadPartialConfig.sync;t.loadPartialConfigSync=p;const f=i.loadPartialConfig.async;t.loadPartialConfigAsync=f;const d=c(a);t.loadOptions=d;const h=a.sync;t.loadOptionsSync=h;const m=a.async;t.loadOptionsAsync=m;const y=l.sync;t.createConfigItemSync=y;const g=l.async;t.createConfigItemAsync=g},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,t.default=class{constructor(e,t,r){this.key=void 0,this.manipulateOptions=void 0,this.post=void 0,this.pre=void 0,this.visitor=void 0,this.parserOverride=void 0,this.generatorOverride=void 0,this.options=void 0,this.key=e.name||r,this.manipulateOptions=e.manipulateOptions,this.post=e.post,this.pre=e.pre,this.visitor=e.visitor||{},this.parserOverride=e.parserOverride,this.generatorOverride=e.generatorOverride,this.options=t}}},(e,t,r)=>{"use strict";function n(){const e=r(8);return n=function(){return e},e}Object.defineProperty(t,"__esModule",{value:!0}),t.createItemFromDescriptor=i,t.createConfigItem=function*(e,{dirname:t=".",type:r}={}){return i(yield*(0,s.createDescriptor)(e,n().resolve(t),{type:r,alias:"programmatic item"}))},t.getItemDescriptor=function(e){if(null!=e&&e[o])return e._descriptor};var s=r(288);function i(e){return new a(e)}const o=Symbol.for("@babel/core@7 - ConfigItem");class a{constructor(e){this._descriptor=void 0,this[o]=!0,this.value=void 0,this.options=void 0,this.dirname=void 0,this.name=void 0,this.file=void 0,this._descriptor=e,Object.defineProperty(this,"_descriptor",{enumerable:!1}),Object.defineProperty(this,o,{enumerable:!1}),this.value=this._descriptor.value,this.options=this._descriptor.options,this.dirname=this._descriptor.dirname,this.name=this._descriptor.name,this.file=this._descriptor.file?{request:this._descriptor.file.request,resolved:this._descriptor.file.resolved}:void 0,Object.freeze(this)}}Object.freeze(a.prototype)},(e,t,r)=>{"use strict";function n(){const e=r(14);return n=function(){return e},e}Object.defineProperty(t,"__esModule",{value:!0}),t.makeWeakCache=l,t.makeWeakCacheSync=function(e){return o(l(e))},t.makeStrongCache=c,t.makeStrongCacheSync=function(e){return o(c(e))},t.assertSimpleType=h;var s=r(287),i=r(150);const o=e=>n()(e).sync;function*a(){return!0}function l(e){return u(WeakMap,e)}function c(e){return u(Map,e)}function u(e,t){const r=new e,n=new e,o=new e;return function*(e,a){const l=yield*(0,s.isAsync)(),c=l?n:r,u=yield*function*(e,t,r,n,i){const o=yield*p(t,n,i);if(o.valid)return o;if(e){const e=yield*p(r,n,i);if(e.valid)return{valid:!0,value:yield*(0,s.waitFor)(e.value.promise)}}return{valid:!1,value:null}}(l,c,o,e,a);if(u.valid)return u.value;const h=new d(a),y=t(e,h);let g,b;if((0,i.isIterableIterator)(y)){const t=y;b=yield*(0,s.onFirstPause)(t,(()=>{g=function(e,t,r){const n=new m;return f(t,e,r,n),n}(h,o,e)}))}else b=y;return f(c,h,e,b),g&&(o.delete(e),g.release(b)),b}}function*p(e,t,r){const n=e.get(t);if(n)for(const{value:e,valid:t}of n)if(yield*t(r))return{valid:!0,value:e};return{valid:!1,value:null}}function f(e,t,r,n){t.configured()||t.forever();let s=e.get(r);switch(t.deactivate(),t.mode()){case"forever":s=[{value:n,valid:a}],e.set(r,s);break;case"invalidate":s=[{value:n,valid:t.validator()}],e.set(r,s);break;case"valid":s?s.push({value:n,valid:t.validator()}):(s=[{value:n,valid:t.validator()}],e.set(r,s))}}class d{constructor(e){this._active=!0,this._never=!1,this._forever=!1,this._invalidate=!1,this._configured=!1,this._pairs=[],this._data=void 0,this._data=e}simple(){return function(e){function t(t){if("boolean"!=typeof t)return e.using((()=>h(t())));t?e.forever():e.never()}return t.forever=()=>e.forever(),t.never=()=>e.never(),t.using=t=>e.using((()=>h(t()))),t.invalidate=t=>e.invalidate((()=>h(t()))),t}(this)}mode(){return this._never?"never":this._forever?"forever":this._invalidate?"invalidate":"valid"}forever(){if(!this._active)throw new Error("Cannot change caching after evaluation has completed.");if(this._never)throw new Error("Caching has already been configured with .never()");this._forever=!0,this._configured=!0}never(){if(!this._active)throw new Error("Cannot change caching after evaluation has completed.");if(this._forever)throw new Error("Caching has already been configured with .forever()");this._never=!0,this._configured=!0}using(e){if(!this._active)throw new Error("Cannot change caching after evaluation has completed.");if(this._never||this._forever)throw new Error("Caching has already been configured with .never or .forever()");this._configured=!0;const t=e(this._data),r=(0,s.maybeAsync)(e,"You appear to be using an async cache handler, but Babel has been called synchronously");return(0,s.isThenable)(t)?t.then((e=>(this._pairs.push([e,r]),e))):(this._pairs.push([t,r]),t)}invalidate(e){return this._invalidate=!0,this.using(e)}validator(){const e=this._pairs;return function*(t){for(const[r,n]of e)if(r!==(yield*n(t)))return!1;return!0}}deactivate(){this._active=!1}configured(){return this._configured}}function h(e){if((0,s.isThenable)(e))throw new Error("You appear to be using an async cache handler, which your current version of Babel does not support. We may add support for this in the future, but if you're on the most recent version of @babel/core and still seeing this error, then you'll need to synchronously handle your caching logic.");if(null!=e&&"string"!=typeof e&&"boolean"!=typeof e&&"number"!=typeof e)throw new Error("Cache keys must be either string, boolean, number, null, or undefined.");return e}class m{constructor(){this.released=!1,this.promise=void 0,this._resolve=void 0,this.promise=new Promise((e=>{this._resolve=e}))}release(e){this.released=!0,this._resolve(e)}}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.validate=function(e,t){return p({type:"root",source:e},t)},t.checkNoUnwrappedItemOptionPairs=function(e,t,r,n){if(0===t)return;const s=e[t-1],i=e[t];s.file&&void 0===s.options&&"object"==typeof i.value&&(n.message+=`\n- Maybe you meant to use\n"${r}": [\n ["${s.file.request}", ${JSON.stringify(i.value,void 0,2)}]\n]\nTo be a valid ${r}, its name and options should be wrapped in a pair of brackets`)},t.assumptionsNames=void 0,r(79);var n=r(481),s=r(301);const i={cwd:s.assertString,root:s.assertString,rootMode:s.assertRootMode,configFile:s.assertConfigFileSearch,caller:s.assertCallerMetadata,filename:s.assertString,filenameRelative:s.assertString,code:s.assertBoolean,ast:s.assertBoolean,cloneInputAst:s.assertBoolean,envName:s.assertString},o={babelrc:s.assertBoolean,babelrcRoots:s.assertBabelrcSearch},a={extends:s.assertString,ignore:s.assertIgnoreList,only:s.assertIgnoreList,targets:s.assertTargets,browserslistConfigFile:s.assertConfigFileSearch,browserslistEnv:s.assertString},l={inputSourceMap:s.assertInputSourceMap,presets:s.assertPluginList,plugins:s.assertPluginList,passPerPreset:s.assertBoolean,assumptions:s.assertAssumptions,env:function(e,t){if("env"===e.parent.type)throw new Error(`${(0,s.msg)(e)} is not allowed inside of another .env block`);const r=e.parent,n=(0,s.assertObject)(e,t);if(n)for(const t of Object.keys(n)){const i=(0,s.assertObject)((0,s.access)(e,t),n[t]);i&&p({type:"env",name:t,parent:r},i)}return n},overrides:function(e,t){if("env"===e.parent.type)throw new Error(`${(0,s.msg)(e)} is not allowed inside an .env block`);if("overrides"===e.parent.type)throw new Error(`${(0,s.msg)(e)} is not allowed inside an .overrides block`);const r=e.parent,n=(0,s.assertArray)(e,t);if(n)for(const[t,i]of n.entries()){const n=(0,s.access)(e,t),o=(0,s.assertObject)(n,i);if(!o)throw new Error(`${(0,s.msg)(n)} must be an object`);p({type:"overrides",index:t,parent:r},o)}return n},test:s.assertConfigApplicableTest,include:s.assertConfigApplicableTest,exclude:s.assertConfigApplicableTest,retainLines:s.assertBoolean,comments:s.assertBoolean,shouldPrintComment:s.assertFunction,compact:s.assertCompact,minified:s.assertBoolean,auxiliaryCommentBefore:s.assertString,auxiliaryCommentAfter:s.assertString,sourceType:s.assertSourceType,wrapPluginVisitorMethod:s.assertFunction,highlightCode:s.assertBoolean,sourceMaps:s.assertSourceMaps,sourceMap:s.assertSourceMaps,sourceFileName:s.assertString,sourceRoot:s.assertString,parserOpts:s.assertObject,generatorOpts:s.assertObject};Object.assign(l,{getModuleId:s.assertFunction,moduleRoot:s.assertString,moduleIds:s.assertBoolean,moduleId:s.assertString});const c=new Set(["arrayLikeIsIterable","constantReexports","constantSuper","enumerableModuleMeta","ignoreFunctionLength","ignoreToPrimitiveHint","iterableIsArray","mutableTemplateObject","noClassCalls","noDocumentAll","noNewArrows","objectRestNoSymbols","privateFieldsAsProperties","pureGetters","setClassMethods","setComputedProperties","setPublicClassFields","setSpreadProperties","skipForOfIteratorClosing","superIsCallableConstructor"]);function u(e){return"root"===e.type?e.source:u(e.parent)}function p(e,t){const r=u(e);return function(e){if(d(e,"sourceMap")&&d(e,"sourceMaps"))throw new Error(".sourceMap is an alias for .sourceMaps, cannot use both")}(t),Object.keys(t).forEach((n=>{const c={type:"option",name:n,parent:e};if("preset"===r&&a[n])throw new Error(`${(0,s.msg)(c)} is not allowed in preset options`);if("arguments"!==r&&i[n])throw new Error(`${(0,s.msg)(c)} is only allowed in root programmatic options`);if("arguments"!==r&&"configfile"!==r&&o[n]){if("babelrcfile"===r||"extendsfile"===r)throw new Error(`${(0,s.msg)(c)} is not allowed in .babelrc or "extends"ed files, only in root programmatic options, or babel.config.js/config file options`);throw new Error(`${(0,s.msg)(c)} is only allowed in root programmatic options, or babel.config.js/config file options`)}(l[n]||a[n]||o[n]||i[n]||f)(c,t[n])})),t}function f(e){const t=e.name;if(n.default[t]){const{message:r,version:i=5}=n.default[t];throw new Error(`Using removed Babel ${i} option: ${(0,s.msg)(e)} - ${r}`)}{const t=new Error(`Unknown option: ${(0,s.msg)(e)}. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.`);throw t.code="BABEL_UNKNOWN_OPTION",t}}function d(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.assumptionsNames=c},(e,t,r)=>{"use strict";e.exports=r(507)},(e,t,r)=>{"use strict";var n=r(7);let s=r(85),i=r(47),o=r(156),a=r(22),l=r(308),c=r(86),u=r(309),p=r(87),f=r(160),d=r(49),h=r(88),m=r(159),y=r(90),g=r(161),b=r(162),v=r(89),E=r(35),x=r(48);function S(...e){return 1===e.length&&Array.isArray(e[0])&&(e=e[0]),new l(e)}S.plugin=function(e,t){function r(...r){let n=t(...r);return n.postcssPlugin=e,n.postcssVersion=(new l).version,n}let s;return console&&console.warn&&n.env.LANG&&n.env.LANG.startsWith("cn"),Object.defineProperty(r,"postcss",{get:()=>(s||(s=r()),s)}),r.process=function(e,t,n){return S([r(n)]).process(e,t)},r},S.stringify=c,S.parse=g,S.fromJSON=u,S.list=b,S.comment=e=>new d(e),S.atRule=e=>new h(e),S.decl=e=>new i(e),S.rule=e=>new v(e),S.root=e=>new E(e),S.document=e=>new p(e),S.CssSyntaxError=s,S.Declaration=i,S.Container=a,S.Document=p,S.Comment=d,S.Warning=f,S.AtRule=h,S.Result=m,S.Input=y,S.Rule=v,S.Root=E,S.Node=x,o.registerPostcss(S),e.exports=S,S.default=S},(e,t,r)=>{"use strict";let{red:n,bold:s,gray:i,options:o}=r(513),a=r(319);class l extends Error{constructor(e,t,r,n,s,i){super(e),this.name="CssSyntaxError",this.reason=e,s&&(this.file=s),n&&(this.source=n),i&&(this.plugin=i),void 0!==t&&void 0!==r&&(this.line=t,this.column=r),this.setMessage(),Error.captureStackTrace&&Error.captureStackTrace(this,l)}setMessage(){this.message=this.plugin?this.plugin+": ":"",this.message+=this.file?this.file:"",void 0!==this.line&&(this.message+=":"+this.line+":"+this.column),this.message+=": "+this.reason}showSourceCode(e){if(!this.source)return"";let t=this.source;null==e&&(e=o.enabled),a&&e&&(t=a(t));let r,l,c=t.split(/\r?\n/),u=Math.max(this.line-3,0),p=Math.min(this.line+2,c.length),f=String(p).length;return e?(r=e=>s(n(e)),l=e=>i(e)):r=l=e=>e,c.slice(u,p).map(((e,t)=>{let n=u+1+t,s=" "+(" "+n).slice(-f)+" | ";if(n===this.line){let t=l(s.replace(/\d/g," "))+e.slice(0,this.column-1).replace(/[^\t]/g," ");return r(">")+l(s)+e+"\n "+t+r("^")}return" "+l(s)+e})).join("\n")}toString(){let e=this.showSourceCode();return e&&(e="\n\n"+e+"\n"),this.name+": "+this.message+e}}e.exports=l,l.default=l},(e,t,r)=>{"use strict";let n=r(155);function s(e,t){new n(t).stringify(e)}e.exports=s,s.default=s},(e,t,r)=>{"use strict";let n,s,i=r(22);class o extends i{constructor(e){super({type:"document",...e}),this.nodes||(this.nodes=[])}toResult(e={}){return new n(new s,this,e).stringify()}}o.registerLazyResult=e=>{n=e},o.registerProcessor=e=>{s=e},e.exports=o,o.default=o},(e,t,r)=>{"use strict";let n=r(22);class s extends n{constructor(e){super(e),this.type="atrule"}append(...e){return this.proxyOf.nodes||(this.nodes=[]),super.append(...e)}prepend(...e){return this.proxyOf.nodes||(this.nodes=[]),super.prepend(...e)}}e.exports=s,s.default=s,n.registerAtRule(s)},(e,t,r)=>{"use strict";let n=r(22),s=r(162);class i extends n{constructor(e){super(e),this.type="rule",this.nodes||(this.nodes=[])}get selectors(){return s.comma(this.selector)}set selectors(e){let t=this.selector?this.selector.match(/,\s*/):null,r=t?t[0]:","+this.raw("between","beforeOpen");this.selector=e.join(r)}}e.exports=i,i.default=i,n.registerRule(i)},(e,t,r)=>{"use strict";let{SourceMapConsumer:n,SourceMapGenerator:s}=r(157),{fileURLToPath:i,pathToFileURL:o}=r(321),{resolve:a,isAbsolute:l}=r(158),{nanoid:c}=r(325),u=r(319),p=r(85),f=r(163),d=Symbol("fromOffsetCache"),h=Boolean(n&&s),m=Boolean(a&&l);class y{constructor(e,t={}){if(null==e||"object"==typeof e&&!e.toString)throw new Error(`PostCSS received ${e} instead of CSS string`);if(this.css=e.toString(),"\ufeff"===this.css[0]||"￾"===this.css[0]?(this.hasBOM=!0,this.css=this.css.slice(1)):this.hasBOM=!1,t.from&&(!m||/^\w+:\/\//.test(t.from)||l(t.from)?this.file=t.from:this.file=a(t.from)),m&&h){let e=new f(this.css,t);if(e.text){this.map=e;let t=e.consumer().file;!this.file&&t&&(this.file=this.mapResolve(t))}}this.file||(this.id=""),this.map&&(this.map.file=this.from)}fromOffset(e){let t,r;if(this[d])r=this[d];else{let e=this.css.split("\n");r=new Array(e.length);let t=0;for(let n=0,s=e.length;n=t)n=r.length-1;else{let t,s=r.length-2;for(;n>1),e=r[t+1])){n=t;break}n=t+1}}return{line:n+1,col:e-r[n]+1}}error(e,t,r,n={}){let s;if(!r){let e=this.fromOffset(t);t=e.line,r=e.col}let i=this.origin(t,r);return s=i?new p(e,i.line,i.column,i.source,i.file,n.plugin):new p(e,t,r,this.css,this.file,n.plugin),s.input={line:t,column:r,source:this.css},this.file&&(o&&(s.input.url=o(this.file).toString()),s.input.file=this.file),s}origin(e,t){if(!this.map)return!1;let r,n=this.map.consumer(),s=n.originalPositionFor({line:e,column:t});if(!s.source)return!1;r=l(s.source)?o(s.source):new URL(s.source,this.map.consumer().sourceRoot||o(this.map.mapFile));let a={url:r.toString(),line:s.line,column:s.column};if("file:"===r.protocol){if(!i)throw new Error("file: protocol is not available in this PostCSS build");a.file=i(r)}let c=n.sourceContentFor(s.source);return c&&(a.source=c),a}mapResolve(e){return/^\w+:\/\//.test(e)?e:a(this.map.consumer().sourceRoot||this.map.root||".",e)}get from(){return this.file||this.id}toJSON(){let e={};for(let t of["hasBOM","css","file","id"])null!=this[t]&&(e[t]=this[t]);return this.map&&(e.map={...this.map},e.map.consumerCache&&(e.map.consumerCache=void 0)),e}}e.exports=y,y.default=y,u&&u.registerInput&&u.registerInput(y)},(e,t,r)=>{"use strict";t.__esModule=!0,t.stripComments=t.ensureObject=t.getProp=t.unesc=void 0;var n=a(r(98));t.unesc=n.default;var s=a(r(174));t.getProp=s.default;var i=a(r(175));t.ensureObject=i.default;var o=a(r(176));function a(e){return e&&e.__esModule?e:{default:e}}t.stripComments=o.default},e=>{"use strict"; /*! https://mths.be/cssesc v3.0.0 by @mathias */var t={}.hasOwnProperty,r=/[ -,\.\/:-@\[-\^`\{-~]/,n=/[ -,\.\/:-@\[\]\^`\{-~]/,s=/(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g,i=function e(i,o){"single"!=(o=function(e,r){if(!e)return r;var n={};for(var s in r)n[s]=t.call(e,s)?e[s]:r[s];return n}(o,e.options)).quotes&&"double"!=o.quotes&&(o.quotes="single");for(var a="double"==o.quotes?'"':"'",l=o.isIdentifier,c=i.charAt(0),u="",p=0,f=i.length;p126){if(h>=55296&&h<=56319&&p{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createClassFeaturePlugin=function({name:e,feature:t,loose:r,manipulateOptions:f,api:d={assumption:()=>{}}}){const h=d.assumption("setPublicClassFields"),m=d.assumption("privateFieldsAsProperties"),y=d.assumption("constantSuper"),g=d.assumption("noDocumentAll");if(!0===r){const e=[];void 0!==h&&e.push('"setPublicClassFields"'),void 0!==m&&e.push('"privateFieldsAsProperties"'),e.length}return{name:e,manipulateOptions:f,pre(){(0,c.enableFeature)(this.file,t,r),(!this.file.get(p)||this.file.get(p)0&&(0,l.injectInitialization)(e,f,k,((e,t)=>{if(!d)for(const r of b)r.node.static||r.traverse(e,t)})),(e=N(e)).insertBefore([...A,...O]),C.length>0&&e.insertAfter(C),I.length>0&&e.find((e=>e.isStatement()||e.isDeclaration())).insertAfter(I)},PrivateName(e){if(this.file.get(p)===u&&!e.parentPath.isPrivate({key:e.node}))throw e.buildCodeFrameError(`Unknown PrivateName "${e}"`)},ExportDefaultDeclaration(e){if(this.file.get(p)!==u)return;const t=e.get("declaration");t.isClassDeclaration()&&(0,a.hasDecorators)(t.node)&&(t.node.id?(0,i.default)(e):t.node.type="ClassExpression")}}}},Object.defineProperty(t,"injectInitialization",{enumerable:!0,get:function(){return l.injectInitialization}}),Object.defineProperty(t,"enableFeature",{enumerable:!0,get:function(){return c.enableFeature}}),Object.defineProperty(t,"FEATURES",{enumerable:!0,get:function(){return c.FEATURES}});var n=r(9),s=r(134),i=r(132),o=r(537),a=r(311),l=r(539),c=r(540);const u="7.14.6".split(".").reduce(((e,t)=>1e5*e+ +t),0),p="@babel/plugin-class-features/version"},e=>{const t=/^[0-9]+$/,r=(e,r)=>{const n=t.test(e),s=t.test(r);return n&&s&&(e=+e,r=+r),e===r?0:n&&!s?-1:s&&!n?1:er(t,e)}},function(e,t){!function(e){"use strict";class t{constructor(){this.should_skip=!1,this.should_remove=!1,this.replacement=null,this.context={skip:()=>this.should_skip=!0,remove:()=>this.should_remove=!0,replace:e=>this.replacement=e}}replace(e,t,r,n){e&&(null!==r?e[t][r]=n:e[t]=n)}remove(e,t,r){e&&(null!==r?e[t].splice(r,1):delete e[t])}}class r extends t{constructor(e,t){super(),this.enter=e,this.leave=t}visit(e,t,r,n){if(e){if(this.enter){const s=this.should_skip,i=this.should_remove,o=this.replacement;this.should_skip=!1,this.should_remove=!1,this.replacement=null,this.enter.call(this.context,e,t,r,n),this.replacement&&(e=this.replacement,this.replace(t,r,n,e)),this.should_remove&&this.remove(t,r,n);const a=this.should_skip,l=this.should_remove;if(this.should_skip=s,this.should_remove=i,this.replacement=o,a)return e;if(l)return null}for(const t in e){const r=e[t];if("object"==typeof r)if(Array.isArray(r))for(let n=0;n{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(172))&&n.__esModule?n:{default:n},i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if(Object.prototype.hasOwnProperty.call(e,s)){var i=n?Object.getOwnPropertyDescriptor(e,s):null;i&&(i.get||i.set)?Object.defineProperty(r,s,i):r[s]=e[s]}return r.default=e,t&&t.set(e,r),r}(r(166));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}var a=function(e){return new s.default(e)};Object.assign(a,i),delete a.__esModule;var l=a;t.default=l,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(52))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){for(var r=0;r{"use strict";function r(e){for(var t=e.toLowerCase(),r="",n=!1,s=0;s<6&&void 0!==t[s];s++){var i=t.charCodeAt(s);if(n=32===i,!(i>=97&&i<=102||i>=48&&i<=57))break;r+=t[s]}if(0!==r.length){var o=parseInt(r,16);return o>=55296&&o<=57343||0===o||o>1114111?["�",r.length+(n?1:0)]:[String.fromCodePoint(o),r.length+(n?1:0)]}}t.__esModule=!0,t.default=function(e){if(!n.test(e))return e;for(var t="",s=0;s{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(52))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.SELECTOR,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n=a(r(92)),s=r(91),i=a(r(15)),o=r(5);function a(e){return e&&e.__esModule?e:{default:e}}function l(e,t){for(var r=0;r{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.COMMENT,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.ID,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n.prototype.valueToString=function(){return"#"+e.prototype.valueToString.call(this)},n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(53))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.TAG,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.STRING,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(52))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.PSEUDO,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n.prototype.toString=function(){var e=this.length?"("+this.map(String).join(",")+")":"";return[this.rawSpaceBefore,this.stringifyProperty("value"),e,this.rawSpaceAfter].join("")},n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(53))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.UNIVERSAL,r.value="*",r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.COMBINATOR,r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(15))&&n.__esModule?n:{default:n},i=r(5);function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var a=function(e){var t,r;function n(t){var r;return(r=e.call(this,t)||this).type=i.NESTING,r.value="&",r}return r=e,(t=n).prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r),n}(s.default);t.default=a,e.exports=t.default},(e,t,r)=>{var n=r(110);e.exports=function(e){return Object(n(e))}},e=>{e.exports=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e}},(e,t,r)=>{var n=r(183),s=r(55);(e.exports=function(e,t){return s[e]||(s[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.15.2",mode:n?"pure":"global",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"})},(e,t,r)=>{var n=r(31),s=r(113),i=r(57),o=r(115),a=Object.defineProperty;t.f=n?a:function(e,t,r){if(i(e),t=o(t,!0),i(r),s)try{return a(e,t,r)}catch(e){}if("get"in r||"set"in r)throw TypeError("Accessors not supported");return"value"in r&&(e[t]=r.value),e}},(e,t,r)=>{var n=r(31),s=r(16),i=r(114);e.exports=!n&&!s((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},(e,t,r)=>{var n=r(2),s=r(24),i=n.document,o=s(i)&&s(i.createElement);e.exports=function(e){return o?i.createElement(e):{}}},(e,t,r)=>{var n=r(24);e.exports=function(e,t){if(!n(e))return e;var r,s;if(t&&"function"==typeof(r=e.toString)&&!n(s=r.call(e)))return s;if("function"==typeof(r=e.valueOf)&&!n(s=r.call(e)))return s;if(!t&&"function"==typeof(r=e.toString)&&!n(s=r.call(e)))return s;throw TypeError("Can't convert object to primitive value")}},e=>{e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},(e,t,r)=>{var n=r(118),s=r(16);e.exports=!!Object.getOwnPropertySymbols&&!s((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&n&&n<41}))},(e,t,r)=>{var n,s,i=r(2),o=r(33),a=i.process,l=a&&a.versions,c=l&&l.v8;c?s=(n=c.split("."))[0]<4?1:n[0]+n[1]:o&&(!(n=o.match(/Edge\/(\d+)/))||n[1]>=74)&&(n=o.match(/Chrome\/(\d+)/))&&(s=n[1]),e.exports=s&&+s},(e,t,r)=>{var n=r(2),s=r(32),i=r(17),o=r(56),a=r(120),l=r(186),c=l.get,u=l.enforce,p=String(String).split("String");(e.exports=function(e,t,r,a){var l,c=!!a&&!!a.unsafe,f=!!a&&!!a.enumerable,d=!!a&&!!a.noTargetGet;"function"==typeof r&&("string"!=typeof t||i(r,"name")||s(r,"name",t),(l=u(r)).source||(l.source=p.join("string"==typeof t?t:""))),e!==n?(c?!d&&e[t]&&(f=!0):delete e[t],f?e[t]=r:s(e,t,r)):f?e[t]=r:o(t,r)})(Function.prototype,"toString",(function(){return"function"==typeof this&&c(this).source||a(this)}))},(e,t,r)=>{var n=r(55),s=Function.toString;"function"!=typeof n.inspectSource&&(n.inspectSource=function(e){return s.call(e)}),e.exports=n.inspectSource},(e,t,r)=>{var n=r(111),s=r(58),i=n("keys");e.exports=function(e){return i[e]||(i[e]=s(e))}},e=>{e.exports={}},e=>{e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},(e,t,r)=>{var n=r(125),s=Math.min;e.exports=function(e){return e>0?s(n(e),9007199254740991):0}},e=>{var t=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:t)(e)}},(e,t,r)=>{"use strict";function n(){const e=r(211);return n=function(){return e},e}function s(){const e=r(10);return s=function(){return e},e}function i(){const e=r(39);return i=function(){return e},e}function o(){const e=r(0);return o=function(){return e},e}function a(){const e=r(239);return a=function(){return e},e}function l(){const e=r(28);return l=function(){return e},e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;const c={enter(e,t){const r=e.node.loc;r&&(t.loc=r,e.stop())}};class u{constructor(e,{code:t,ast:r,inputMap:n}){this._map=new Map,this.opts=void 0,this.declarations={},this.path=null,this.ast={},this.scope=void 0,this.metadata={},this.code="",this.inputMap=null,this.hub={file:this,getCode:()=>this.code,getScope:()=>this.scope,addHelper:this.addHelper.bind(this),buildError:this.buildCodeFrameError.bind(this)},this.opts=e,this.code=t,this.ast=r,this.inputMap=n,this.path=s().NodePath.get({hub:this.hub,parentPath:null,parent:this.ast,container:this.ast,key:"program"}).setContext(),this.scope=this.path.scope}get shebang(){const{interpreter:e}=this.path.node;return e?e.value:""}set shebang(e){e?this.path.get("interpreter").replaceWith(o().interpreterDirective(e)):this.path.get("interpreter").remove()}set(e,t){if("helpersNamespace"===e)throw new Error("Babel 7.0.0-beta.56 has dropped support for the 'helpersNamespace' utility.If you are using @babel/plugin-external-helpers you will need to use a newer version than the one you currently have installed. If you have your own implementation, you'll want to explore using 'helperGenerator' alongside 'file.availableHelper()'.");this._map.set(e,t)}get(e){return this._map.get(e)}has(e){return this._map.has(e)}getModuleName(){return(0,a().getModuleName)(this.opts,this.opts)}addImport(){throw new Error("This API has been removed. If you're looking for this functionality in Babel 7, you should import the '@babel/helper-module-imports' module and use the functions exposed from that module, such as 'addNamed' or 'addDefault'.")}availableHelper(e,t){let r;try{r=n().minVersion(e)}catch(e){if("BABEL_HELPER_UNKNOWN"!==e.code)throw e;return!1}return"string"!=typeof t||(l().valid(t)&&(t=`^${t}`),!l().intersects(`<${r}`,t)&&!l().intersects(">=8.0.0",t))}addHelper(e){const t=this.declarations[e];if(t)return o().cloneNode(t);const r=this.get("helperGenerator");if(r){const t=r(e);if(t)return t}n().ensure(e,u);const s=this.declarations[e]=this.scope.generateUidIdentifier(e),i={};for(const t of n().getDependencies(e))i[t]=this.addHelper(t);const{nodes:a,globals:l}=n().get(e,(e=>i[e]),s,Object.keys(this.scope.getAllBindings()));return l.forEach((e=>{this.path.scope.hasBinding(e,!0)&&this.path.scope.rename(e)})),a.forEach((e=>{e._compact=!0})),this.path.unshiftContainer("body",a),this.path.get("body").forEach((e=>{-1!==a.indexOf(e.node)&&e.isVariableDeclaration()&&this.scope.registerDeclaration(e)})),s}addTemplateObject(){throw new Error("This function has been moved into the template literal transform itself.")}buildCodeFrameError(e,t,r=SyntaxError){let n=e&&(e.loc||e._loc);if(!n&&e){const r={loc:null};(0,s().default)(e,c,this.scope,r),n=r.loc;let i="This is an error on an internal node. Probably an internal error.";n&&(i+=" Location has been estimated."),t+=` (${i})`}if(n){const{highlightCode:e=!0}=this.opts;t+="\n"+(0,i().codeFrameColumns)(this.code,{start:{line:n.start.line,column:n.start.column+1},end:n.end&&n.start.line===n.end.line?{line:n.end.line,column:n.end.column+1}:void 0},{highlightCode:e})}return new r(t)}}t.default=u},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const r=Object.keys(t);for(const n of r)if(e[n]!==t[n])return!1;return!0}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.classMethodOrDeclareMethodCommon=t.classMethodOrPropertyCommon=t.patternLikeCommon=t.functionDeclarationCommon=t.functionTypeAnnotationCommon=t.functionCommon=void 0,r(62),r(38),r(63);var n=r(25),s=r(20);(0,s.default)("ArrayExpression",{fields:{elements:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeOrValueType)("null","Expression","SpreadElement"))),default:[]}},visitor:["elements"],aliases:["Expression"]}),(0,s.default)("AssignmentExpression",{fields:{operator:{validate:(0,s.assertValueType)("string")},left:{validate:(0,s.assertNodeType)("LVal")},right:{validate:(0,s.assertNodeType)("Expression")}},builder:["operator","left","right"],visitor:["left","right"],aliases:["Expression"]}),(0,s.default)("BinaryExpression",{builder:["operator","left","right"],fields:{operator:{validate:(0,s.assertOneOf)(...n.BINARY_OPERATORS)},left:{validate:function(){const e=(0,s.assertNodeType)("Expression"),t=(0,s.assertNodeType)("Expression","PrivateName"),r=function(r,n,s){("in"===r.operator?t:e)(r,n,s)};return r.oneOfNodeTypes=["Expression","PrivateName"],r}()},right:{validate:(0,s.assertNodeType)("Expression")}},visitor:["left","right"],aliases:["Binary","Expression"]}),(0,s.default)("InterpreterDirective",{builder:["value"],fields:{value:{validate:(0,s.assertValueType)("string")}}}),(0,s.default)("Directive",{visitor:["value"],fields:{value:{validate:(0,s.assertNodeType)("DirectiveLiteral")}}}),(0,s.default)("DirectiveLiteral",{builder:["value"],fields:{value:{validate:(0,s.assertValueType)("string")}}}),(0,s.default)("BlockStatement",{builder:["body","directives"],visitor:["directives","body"],fields:{directives:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Directive"))),default:[]},body:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Statement")))}},aliases:["Scopable","BlockParent","Block","Statement"]}),(0,s.default)("BreakStatement",{visitor:["label"],fields:{label:{validate:(0,s.assertNodeType)("Identifier"),optional:!0}},aliases:["Statement","Terminatorless","CompletionStatement"]}),(0,s.default)("CallExpression",{visitor:["callee","arguments","typeParameters","typeArguments"],builder:["callee","arguments"],aliases:["Expression"],fields:Object.assign({callee:{validate:(0,s.assertNodeType)("Expression","V8IntrinsicIdentifier")},arguments:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Expression","SpreadElement","JSXNamespacedName","ArgumentPlaceholder")))}},{optional:{validate:(0,s.assertOneOf)(!0,!1),optional:!0}},{typeArguments:{validate:(0,s.assertNodeType)("TypeParameterInstantiation"),optional:!0},typeParameters:{validate:(0,s.assertNodeType)("TSTypeParameterInstantiation"),optional:!0}})}),(0,s.default)("CatchClause",{visitor:["param","body"],fields:{param:{validate:(0,s.assertNodeType)("Identifier","ArrayPattern","ObjectPattern"),optional:!0},body:{validate:(0,s.assertNodeType)("BlockStatement")}},aliases:["Scopable","BlockParent"]}),(0,s.default)("ConditionalExpression",{visitor:["test","consequent","alternate"],fields:{test:{validate:(0,s.assertNodeType)("Expression")},consequent:{validate:(0,s.assertNodeType)("Expression")},alternate:{validate:(0,s.assertNodeType)("Expression")}},aliases:["Expression","Conditional"]}),(0,s.default)("ContinueStatement",{visitor:["label"],fields:{label:{validate:(0,s.assertNodeType)("Identifier"),optional:!0}},aliases:["Statement","Terminatorless","CompletionStatement"]}),(0,s.default)("DebuggerStatement",{aliases:["Statement"]}),(0,s.default)("DoWhileStatement",{visitor:["test","body"],fields:{test:{validate:(0,s.assertNodeType)("Expression")},body:{validate:(0,s.assertNodeType)("Statement")}},aliases:["Statement","BlockParent","Loop","While","Scopable"]}),(0,s.default)("EmptyStatement",{aliases:["Statement"]}),(0,s.default)("ExpressionStatement",{visitor:["expression"],fields:{expression:{validate:(0,s.assertNodeType)("Expression")}},aliases:["Statement","ExpressionWrapper"]}),(0,s.default)("File",{builder:["program","comments","tokens"],visitor:["program"],fields:{program:{validate:(0,s.assertNodeType)("Program")},comments:{validate:Object.assign((()=>{}),{each:{oneOfNodeTypes:["CommentBlock","CommentLine"]}}),optional:!0},tokens:{validate:(0,s.assertEach)(Object.assign((()=>{}),{type:"any"})),optional:!0}}}),(0,s.default)("ForInStatement",{visitor:["left","right","body"],aliases:["Scopable","Statement","For","BlockParent","Loop","ForXStatement"],fields:{left:{validate:(0,s.assertNodeType)("VariableDeclaration","LVal")},right:{validate:(0,s.assertNodeType)("Expression")},body:{validate:(0,s.assertNodeType)("Statement")}}}),(0,s.default)("ForStatement",{visitor:["init","test","update","body"],aliases:["Scopable","Statement","For","BlockParent","Loop"],fields:{init:{validate:(0,s.assertNodeType)("VariableDeclaration","Expression"),optional:!0},test:{validate:(0,s.assertNodeType)("Expression"),optional:!0},update:{validate:(0,s.assertNodeType)("Expression"),optional:!0},body:{validate:(0,s.assertNodeType)("Statement")}}});const i={params:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Identifier","Pattern","RestElement")))},generator:{default:!1},async:{default:!1}};t.functionCommon=i;const o={returnType:{validate:(0,s.assertNodeType)("TypeAnnotation","TSTypeAnnotation","Noop"),optional:!0},typeParameters:{validate:(0,s.assertNodeType)("TypeParameterDeclaration","TSTypeParameterDeclaration","Noop"),optional:!0}};t.functionTypeAnnotationCommon=o;const a=Object.assign({},i,{declare:{validate:(0,s.assertValueType)("boolean"),optional:!0},id:{validate:(0,s.assertNodeType)("Identifier"),optional:!0}});t.functionDeclarationCommon=a,(0,s.default)("FunctionDeclaration",{builder:["id","params","body","generator","async"],visitor:["id","params","body","returnType","typeParameters"],fields:Object.assign({},a,o,{body:{validate:(0,s.assertNodeType)("BlockStatement")}}),aliases:["Scopable","Function","BlockParent","FunctionParent","Statement","Pureish","Declaration"],validate:()=>{}}),(0,s.default)("FunctionExpression",{inherits:"FunctionDeclaration",aliases:["Scopable","Function","BlockParent","FunctionParent","Expression","Pureish"],fields:Object.assign({},i,o,{id:{validate:(0,s.assertNodeType)("Identifier"),optional:!0},body:{validate:(0,s.assertNodeType)("BlockStatement")}})});const l={typeAnnotation:{validate:(0,s.assertNodeType)("TypeAnnotation","TSTypeAnnotation","Noop"),optional:!0},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator")))}};t.patternLikeCommon=l,(0,s.default)("Identifier",{builder:["name"],visitor:["typeAnnotation","decorators"],aliases:["Expression","PatternLike","LVal","TSEntityName"],fields:Object.assign({},l,{name:{validate:(0,s.chain)((0,s.assertValueType)("string"),Object.assign((function(e,t,r){}),{type:"string"}))},optional:{validate:(0,s.assertValueType)("boolean"),optional:!0}}),validate(e,t,r){}}),(0,s.default)("IfStatement",{visitor:["test","consequent","alternate"],aliases:["Statement","Conditional"],fields:{test:{validate:(0,s.assertNodeType)("Expression")},consequent:{validate:(0,s.assertNodeType)("Statement")},alternate:{optional:!0,validate:(0,s.assertNodeType)("Statement")}}}),(0,s.default)("LabeledStatement",{visitor:["label","body"],aliases:["Statement"],fields:{label:{validate:(0,s.assertNodeType)("Identifier")},body:{validate:(0,s.assertNodeType)("Statement")}}}),(0,s.default)("StringLiteral",{builder:["value"],fields:{value:{validate:(0,s.assertValueType)("string")}},aliases:["Expression","Pureish","Literal","Immutable"]}),(0,s.default)("NumericLiteral",{builder:["value"],deprecatedAlias:"NumberLiteral",fields:{value:{validate:(0,s.assertValueType)("number")}},aliases:["Expression","Pureish","Literal","Immutable"]}),(0,s.default)("NullLiteral",{aliases:["Expression","Pureish","Literal","Immutable"]}),(0,s.default)("BooleanLiteral",{builder:["value"],fields:{value:{validate:(0,s.assertValueType)("boolean")}},aliases:["Expression","Pureish","Literal","Immutable"]}),(0,s.default)("RegExpLiteral",{builder:["pattern","flags"],deprecatedAlias:"RegexLiteral",aliases:["Expression","Pureish","Literal"],fields:{pattern:{validate:(0,s.assertValueType)("string")},flags:{validate:(0,s.chain)((0,s.assertValueType)("string"),Object.assign((function(e,t,r){}),{type:"string"})),default:""}}}),(0,s.default)("LogicalExpression",{builder:["operator","left","right"],visitor:["left","right"],aliases:["Binary","Expression"],fields:{operator:{validate:(0,s.assertOneOf)(...n.LOGICAL_OPERATORS)},left:{validate:(0,s.assertNodeType)("Expression")},right:{validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("MemberExpression",{builder:["object","property","computed","optional"],visitor:["object","property"],aliases:["Expression","LVal"],fields:Object.assign({object:{validate:(0,s.assertNodeType)("Expression")},property:{validate:function(){const e=(0,s.assertNodeType)("Identifier","PrivateName"),t=(0,s.assertNodeType)("Expression"),r=function(r,n,s){(r.computed?t:e)(r,n,s)};return r.oneOfNodeTypes=["Expression","Identifier","PrivateName"],r}()},computed:{default:!1}},{optional:{validate:(0,s.assertOneOf)(!0,!1),optional:!0}})}),(0,s.default)("NewExpression",{inherits:"CallExpression"}),(0,s.default)("Program",{visitor:["directives","body"],builder:["body","directives","sourceType","interpreter"],fields:{sourceFile:{validate:(0,s.assertValueType)("string")},sourceType:{validate:(0,s.assertOneOf)("script","module"),default:"script"},interpreter:{validate:(0,s.assertNodeType)("InterpreterDirective"),default:null,optional:!0},directives:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Directive"))),default:[]},body:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Statement")))}},aliases:["Scopable","BlockParent","Block"]}),(0,s.default)("ObjectExpression",{visitor:["properties"],aliases:["Expression"],fields:{properties:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ObjectMethod","ObjectProperty","SpreadElement")))}}}),(0,s.default)("ObjectMethod",{builder:["kind","key","params","body","computed","generator","async"],fields:Object.assign({},i,o,{kind:Object.assign({validate:(0,s.assertOneOf)("method","get","set")},{default:"method"}),computed:{default:!1},key:{validate:function(){const e=(0,s.assertNodeType)("Identifier","StringLiteral","NumericLiteral"),t=(0,s.assertNodeType)("Expression"),r=function(r,n,s){(r.computed?t:e)(r,n,s)};return r.oneOfNodeTypes=["Expression","Identifier","StringLiteral","NumericLiteral"],r}()},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0},body:{validate:(0,s.assertNodeType)("BlockStatement")}}),visitor:["key","params","body","decorators","returnType","typeParameters"],aliases:["UserWhitespacable","Function","Scopable","BlockParent","FunctionParent","Method","ObjectMember"]}),(0,s.default)("ObjectProperty",{builder:["key","value","computed","shorthand","decorators"],fields:{computed:{default:!1},key:{validate:function(){const e=(0,s.assertNodeType)("Identifier","StringLiteral","NumericLiteral"),t=(0,s.assertNodeType)("Expression"),r=function(r,n,s){(r.computed?t:e)(r,n,s)};return r.oneOfNodeTypes=["Expression","Identifier","StringLiteral","NumericLiteral"],r}()},value:{validate:(0,s.assertNodeType)("Expression","PatternLike")},shorthand:{validate:(0,s.chain)((0,s.assertValueType)("boolean"),Object.assign((function(e,t,r){}),{type:"boolean"}),(function(e,t,r){})),default:!1},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0}},visitor:["key","value","decorators"],aliases:["UserWhitespacable","Property","ObjectMember"],validate:((0,s.assertNodeType)("Identifier","Pattern"),(0,s.assertNodeType)("Expression"),function(e,t,r){})}),(0,s.default)("RestElement",{visitor:["argument","typeAnnotation"],builder:["argument"],aliases:["LVal","PatternLike"],deprecatedAlias:"RestProperty",fields:Object.assign({},l,{argument:{validate:(0,s.assertNodeType)("LVal")}}),validate(e,t){}}),(0,s.default)("ReturnStatement",{visitor:["argument"],aliases:["Statement","Terminatorless","CompletionStatement"],fields:{argument:{validate:(0,s.assertNodeType)("Expression"),optional:!0}}}),(0,s.default)("SequenceExpression",{visitor:["expressions"],fields:{expressions:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Expression")))}},aliases:["Expression"]}),(0,s.default)("ParenthesizedExpression",{visitor:["expression"],aliases:["Expression","ExpressionWrapper"],fields:{expression:{validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("SwitchCase",{visitor:["test","consequent"],fields:{test:{validate:(0,s.assertNodeType)("Expression"),optional:!0},consequent:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Statement")))}}}),(0,s.default)("SwitchStatement",{visitor:["discriminant","cases"],aliases:["Statement","BlockParent","Scopable"],fields:{discriminant:{validate:(0,s.assertNodeType)("Expression")},cases:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("SwitchCase")))}}}),(0,s.default)("ThisExpression",{aliases:["Expression"]}),(0,s.default)("ThrowStatement",{visitor:["argument"],aliases:["Statement","Terminatorless","CompletionStatement"],fields:{argument:{validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("TryStatement",{visitor:["block","handler","finalizer"],aliases:["Statement"],fields:{block:{validate:(0,s.chain)((0,s.assertNodeType)("BlockStatement"),Object.assign((function(e){}),{oneOfNodeTypes:["BlockStatement"]}))},handler:{optional:!0,validate:(0,s.assertNodeType)("CatchClause")},finalizer:{optional:!0,validate:(0,s.assertNodeType)("BlockStatement")}}}),(0,s.default)("UnaryExpression",{builder:["operator","argument","prefix"],fields:{prefix:{default:!0},argument:{validate:(0,s.assertNodeType)("Expression")},operator:{validate:(0,s.assertOneOf)(...n.UNARY_OPERATORS)}},visitor:["argument"],aliases:["UnaryLike","Expression"]}),(0,s.default)("UpdateExpression",{builder:["operator","argument","prefix"],fields:{prefix:{default:!1},argument:{validate:(0,s.assertNodeType)("Expression")},operator:{validate:(0,s.assertOneOf)(...n.UPDATE_OPERATORS)}},visitor:["argument"],aliases:["Expression"]}),(0,s.default)("VariableDeclaration",{builder:["kind","declarations"],visitor:["declarations"],aliases:["Statement","Declaration"],fields:{declare:{validate:(0,s.assertValueType)("boolean"),optional:!0},kind:{validate:(0,s.assertOneOf)("var","let","const")},declarations:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("VariableDeclarator")))}},validate(e,t,r){}}),(0,s.default)("VariableDeclarator",{visitor:["id","init"],fields:{id:{validate:(0,s.assertNodeType)("LVal")},definite:{optional:!0,validate:(0,s.assertValueType)("boolean")},init:{optional:!0,validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("WhileStatement",{visitor:["test","body"],aliases:["Statement","BlockParent","Loop","While","Scopable"],fields:{test:{validate:(0,s.assertNodeType)("Expression")},body:{validate:(0,s.assertNodeType)("Statement")}}}),(0,s.default)("WithStatement",{visitor:["object","body"],aliases:["Statement"],fields:{object:{validate:(0,s.assertNodeType)("Expression")},body:{validate:(0,s.assertNodeType)("Statement")}}}),(0,s.default)("AssignmentPattern",{visitor:["left","right","decorators"],builder:["left","right"],aliases:["Pattern","PatternLike","LVal"],fields:Object.assign({},l,{left:{validate:(0,s.assertNodeType)("Identifier","ObjectPattern","ArrayPattern","MemberExpression")},right:{validate:(0,s.assertNodeType)("Expression")},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0}})}),(0,s.default)("ArrayPattern",{visitor:["elements","typeAnnotation"],builder:["elements"],aliases:["Pattern","PatternLike","LVal"],fields:Object.assign({},l,{elements:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeOrValueType)("null","PatternLike")))},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0}})}),(0,s.default)("ArrowFunctionExpression",{builder:["params","body","async"],visitor:["params","body","returnType","typeParameters"],aliases:["Scopable","Function","BlockParent","FunctionParent","Expression","Pureish"],fields:Object.assign({},i,o,{expression:{validate:(0,s.assertValueType)("boolean")},body:{validate:(0,s.assertNodeType)("BlockStatement","Expression")}})}),(0,s.default)("ClassBody",{visitor:["body"],fields:{body:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ClassMethod","ClassPrivateMethod","ClassProperty","ClassPrivateProperty","TSDeclareMethod","TSIndexSignature")))}}}),(0,s.default)("ClassExpression",{builder:["id","superClass","body","decorators"],visitor:["id","body","superClass","mixins","typeParameters","superTypeParameters","implements","decorators"],aliases:["Scopable","Class","Expression"],fields:{id:{validate:(0,s.assertNodeType)("Identifier"),optional:!0},typeParameters:{validate:(0,s.assertNodeType)("TypeParameterDeclaration","TSTypeParameterDeclaration","Noop"),optional:!0},body:{validate:(0,s.assertNodeType)("ClassBody")},superClass:{optional:!0,validate:(0,s.assertNodeType)("Expression")},superTypeParameters:{validate:(0,s.assertNodeType)("TypeParameterInstantiation","TSTypeParameterInstantiation"),optional:!0},implements:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("TSExpressionWithTypeArguments","ClassImplements"))),optional:!0},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0},mixins:{validate:(0,s.assertNodeType)("InterfaceExtends"),optional:!0}}}),(0,s.default)("ClassDeclaration",{inherits:"ClassExpression",aliases:["Scopable","Class","Statement","Declaration"],fields:{id:{validate:(0,s.assertNodeType)("Identifier")},typeParameters:{validate:(0,s.assertNodeType)("TypeParameterDeclaration","TSTypeParameterDeclaration","Noop"),optional:!0},body:{validate:(0,s.assertNodeType)("ClassBody")},superClass:{optional:!0,validate:(0,s.assertNodeType)("Expression")},superTypeParameters:{validate:(0,s.assertNodeType)("TypeParameterInstantiation","TSTypeParameterInstantiation"),optional:!0},implements:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("TSExpressionWithTypeArguments","ClassImplements"))),optional:!0},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0},mixins:{validate:(0,s.assertNodeType)("InterfaceExtends"),optional:!0},declare:{validate:(0,s.assertValueType)("boolean"),optional:!0},abstract:{validate:(0,s.assertValueType)("boolean"),optional:!0}},validate:((0,s.assertNodeType)("Identifier"),function(e,t,r){})}),(0,s.default)("ExportAllDeclaration",{visitor:["source"],aliases:["Statement","Declaration","ModuleDeclaration","ExportDeclaration"],fields:{source:{validate:(0,s.assertNodeType)("StringLiteral")},exportKind:(0,s.validateOptional)((0,s.assertOneOf)("type","value")),assertions:{optional:!0,validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ImportAttribute")))}}}),(0,s.default)("ExportDefaultDeclaration",{visitor:["declaration"],aliases:["Statement","Declaration","ModuleDeclaration","ExportDeclaration"],fields:{declaration:{validate:(0,s.assertNodeType)("FunctionDeclaration","TSDeclareFunction","ClassDeclaration","Expression")}}}),(0,s.default)("ExportNamedDeclaration",{visitor:["declaration","specifiers","source"],aliases:["Statement","Declaration","ModuleDeclaration","ExportDeclaration"],fields:{declaration:{optional:!0,validate:(0,s.chain)((0,s.assertNodeType)("Declaration"),Object.assign((function(e,t,r){}),{oneOfNodeTypes:["Declaration"]}),(function(e,t,r){}))},assertions:{optional:!0,validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ImportAttribute")))},specifiers:{default:[],validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)(function(){const e=(0,s.assertNodeType)("ExportSpecifier","ExportDefaultSpecifier","ExportNamespaceSpecifier");return(0,s.assertNodeType)("ExportSpecifier"),e}()))},source:{validate:(0,s.assertNodeType)("StringLiteral"),optional:!0},exportKind:(0,s.validateOptional)((0,s.assertOneOf)("type","value"))}}),(0,s.default)("ExportSpecifier",{visitor:["local","exported"],aliases:["ModuleSpecifier"],fields:{local:{validate:(0,s.assertNodeType)("Identifier")},exported:{validate:(0,s.assertNodeType)("Identifier","StringLiteral")}}}),(0,s.default)("ForOfStatement",{visitor:["left","right","body"],builder:["left","right","body","await"],aliases:["Scopable","Statement","For","BlockParent","Loop","ForXStatement"],fields:{left:{validate:(0,s.assertNodeType)("VariableDeclaration","LVal")},right:{validate:(0,s.assertNodeType)("Expression")},body:{validate:(0,s.assertNodeType)("Statement")},await:{default:!1}}}),(0,s.default)("ImportDeclaration",{visitor:["specifiers","source"],aliases:["Statement","Declaration","ModuleDeclaration"],fields:{assertions:{optional:!0,validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ImportAttribute")))},specifiers:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("ImportSpecifier","ImportDefaultSpecifier","ImportNamespaceSpecifier")))},source:{validate:(0,s.assertNodeType)("StringLiteral")},importKind:{validate:(0,s.assertOneOf)("type","typeof","value"),optional:!0}}}),(0,s.default)("ImportDefaultSpecifier",{visitor:["local"],aliases:["ModuleSpecifier"],fields:{local:{validate:(0,s.assertNodeType)("Identifier")}}}),(0,s.default)("ImportNamespaceSpecifier",{visitor:["local"],aliases:["ModuleSpecifier"],fields:{local:{validate:(0,s.assertNodeType)("Identifier")}}}),(0,s.default)("ImportSpecifier",{visitor:["local","imported"],aliases:["ModuleSpecifier"],fields:{local:{validate:(0,s.assertNodeType)("Identifier")},imported:{validate:(0,s.assertNodeType)("Identifier","StringLiteral")},importKind:{validate:(0,s.assertOneOf)("type","typeof"),optional:!0}}}),(0,s.default)("MetaProperty",{visitor:["meta","property"],aliases:["Expression"],fields:{meta:{validate:(0,s.chain)((0,s.assertNodeType)("Identifier"),Object.assign((function(e,t,r){}),{oneOfNodeTypes:["Identifier"]}))},property:{validate:(0,s.assertNodeType)("Identifier")}}});const c={abstract:{validate:(0,s.assertValueType)("boolean"),optional:!0},accessibility:{validate:(0,s.assertOneOf)("public","private","protected"),optional:!0},static:{default:!1},override:{default:!1},computed:{default:!1},optional:{validate:(0,s.assertValueType)("boolean"),optional:!0},key:{validate:(0,s.chain)(function(){const e=(0,s.assertNodeType)("Identifier","StringLiteral","NumericLiteral"),t=(0,s.assertNodeType)("Expression");return function(r,n,s){(r.computed?t:e)(r,n,s)}}(),(0,s.assertNodeType)("Identifier","StringLiteral","NumericLiteral","Expression"))}};t.classMethodOrPropertyCommon=c;const u=Object.assign({},i,c,{params:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Identifier","Pattern","RestElement","TSParameterProperty")))},kind:{validate:(0,s.assertOneOf)("get","set","method","constructor"),default:"method"},access:{validate:(0,s.chain)((0,s.assertValueType)("string"),(0,s.assertOneOf)("public","private","protected")),optional:!0},decorators:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Decorator"))),optional:!0}});t.classMethodOrDeclareMethodCommon=u,(0,s.default)("ClassMethod",{aliases:["Function","Scopable","BlockParent","FunctionParent","Method"],builder:["kind","key","params","body","computed","static","generator","async"],visitor:["key","params","body","decorators","returnType","typeParameters"],fields:Object.assign({},u,o,{body:{validate:(0,s.assertNodeType)("BlockStatement")}})}),(0,s.default)("ObjectPattern",{visitor:["properties","typeAnnotation","decorators"],builder:["properties"],aliases:["Pattern","PatternLike","LVal"],fields:Object.assign({},l,{properties:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("RestElement","ObjectProperty")))}})}),(0,s.default)("SpreadElement",{visitor:["argument"],aliases:["UnaryLike"],deprecatedAlias:"SpreadProperty",fields:{argument:{validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("Super",{aliases:["Expression"]}),(0,s.default)("TaggedTemplateExpression",{visitor:["tag","quasi"],aliases:["Expression"],fields:{tag:{validate:(0,s.assertNodeType)("Expression")},quasi:{validate:(0,s.assertNodeType)("TemplateLiteral")},typeParameters:{validate:(0,s.assertNodeType)("TypeParameterInstantiation","TSTypeParameterInstantiation"),optional:!0}}}),(0,s.default)("TemplateElement",{builder:["value","tail"],fields:{value:{validate:(0,s.assertShape)({raw:{validate:(0,s.assertValueType)("string")},cooked:{validate:(0,s.assertValueType)("string"),optional:!0}})},tail:{default:!1}}}),(0,s.default)("TemplateLiteral",{visitor:["quasis","expressions"],aliases:["Expression","Literal"],fields:{quasis:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("TemplateElement")))},expressions:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Expression","TSType")),(function(e,t,r){if(e.quasis.length!==r.length+1)throw new TypeError(`Number of ${e.type} quasis should be exactly one more than the number of expressions.\nExpected ${r.length+1} quasis but got ${e.quasis.length}`)}))}}}),(0,s.default)("YieldExpression",{builder:["argument","delegate"],visitor:["argument"],aliases:["Expression","Terminatorless"],fields:{delegate:{validate:(0,s.chain)((0,s.assertValueType)("boolean"),Object.assign((function(e,t,r){}),{type:"boolean"})),default:!1},argument:{optional:!0,validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("AwaitExpression",{builder:["argument"],visitor:["argument"],aliases:["Expression","Terminatorless"],fields:{argument:{validate:(0,s.assertNodeType)("Expression")}}}),(0,s.default)("Import",{aliases:["Expression"]}),(0,s.default)("BigIntLiteral",{builder:["value"],fields:{value:{validate:(0,s.assertValueType)("string")}},aliases:["Expression","Pureish","Literal","Immutable"]}),(0,s.default)("ExportNamespaceSpecifier",{visitor:["exported"],aliases:["ModuleSpecifier"],fields:{exported:{validate:(0,s.assertNodeType)("Identifier")}}}),(0,s.default)("OptionalMemberExpression",{builder:["object","property","computed","optional"],visitor:["object","property"],aliases:["Expression"],fields:{object:{validate:(0,s.assertNodeType)("Expression")},property:{validate:function(){const e=(0,s.assertNodeType)("Identifier"),t=(0,s.assertNodeType)("Expression"),r=function(r,n,s){(r.computed?t:e)(r,n,s)};return r.oneOfNodeTypes=["Expression","Identifier"],r}()},computed:{default:!1},optional:{validate:(0,s.assertValueType)("boolean")}}}),(0,s.default)("OptionalCallExpression",{visitor:["callee","arguments","typeParameters","typeArguments"],builder:["callee","arguments","optional"],aliases:["Expression"],fields:{callee:{validate:(0,s.assertNodeType)("Expression")},arguments:{validate:(0,s.chain)((0,s.assertValueType)("array"),(0,s.assertEach)((0,s.assertNodeType)("Expression","SpreadElement","JSXNamespacedName","ArgumentPlaceholder")))},optional:{validate:(0,s.assertValueType)("boolean")},typeArguments:{validate:(0,s.assertNodeType)("TypeParameterInstantiation"),optional:!0},typeParameters:{validate:(0,s.assertNodeType)("TSTypeParameterInstantiation"),optional:!0}}})},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){if(e===t)return!0;if(n.ALIAS_KEYS[t])return!1;const r=n.FLIPPED_ALIAS_KEYS[t];if(r){if(r[0]===e)return!0;for(const t of r)if(e===t)return!0}return!1};var n=r(11)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){if(!e)return;const o=n.NODE_FIELDS[e.type];if(!o)return;s(e,t,r,o[t]),i(e,t,r)},t.validateField=s,t.validateChild=i;var n=r(11);function s(e,t,r,n){null!=n&&n.validate&&(n.optional&&null==r||n.validate(e,t,r))}function i(e,t,r){if(null==r)return;const s=n.NODE_PARENT_VALIDATIONS[r.type];s&&s(e,t,r)}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){t&&r&&(t[e]=Array.from(new Set([].concat(t[e],r[e]).filter(Boolean))))}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){if(!e.isExportDeclaration())throw new Error("Only export declarations can be split.");const t=e.isExportDefaultDeclaration(),r=e.get("declaration"),s=r.isClassDeclaration();if(t){const t=r.isFunctionDeclaration()||s,i=r.isScope()?r.scope.parent:r.scope;let o=r.node.id,a=!1;o||(a=!0,o=i.generateUidIdentifier("default"),(t||r.isFunctionExpression()||r.isClassExpression())&&(r.node.id=n.cloneNode(o)));const l=t?r:n.variableDeclaration("var",[n.variableDeclarator(n.cloneNode(o),r.node)]),c=n.exportNamedDeclaration(null,[n.exportSpecifier(n.cloneNode(o),n.identifier("default"))]);return e.insertAfter(c),e.replaceWith(l),a&&i.registerDeclaration(e),e}if(e.get("specifiers").length>0)throw new Error("It doesn't make sense to split exported specifiers.");const i=r.getOuterBindingIdentifiers(),o=Object.keys(i).map((e=>n.exportSpecifier(n.identifier(e),n.identifier(e)))),a=n.exportNamedDeclaration(null,o);return e.insertAfter(a),e.replaceWith(r.node),e};var n=r(0)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){return new i(e,t,r).generate()},t.CodeGenerator=void 0;var n=r(416),s=r(418);class i extends s.default{constructor(e,t={},r){super(function(e,t){const r={auxiliaryCommentBefore:t.auxiliaryCommentBefore,auxiliaryCommentAfter:t.auxiliaryCommentAfter,shouldPrintComment:t.shouldPrintComment,retainLines:t.retainLines,retainFunctionParens:t.retainFunctionParens,comments:null==t.comments||t.comments,compact:t.compact,minified:t.minified,concise:t.concise,indent:{adjustMultilineComment:!0,style:" ",base:0},decoratorsBeforeExport:!!t.decoratorsBeforeExport,jsescOption:Object.assign({quotes:"double",wrap:!0,minimal:!1},t.jsescOption),recordAndTupleSyntaxType:t.recordAndTupleSyntaxType};return r.jsonCompatibleStrings=t.jsonCompatibleStrings,r.minified?(r.compact=!0,r.shouldPrintComment=r.shouldPrintComment||(()=>r.comments)):r.shouldPrintComment=r.shouldPrintComment||(e=>r.comments||e.indexOf("@license")>=0||e.indexOf("@preserve")>=0),"auto"===r.compact&&(r.compact=e.length>5e5,r.compact),r.compact&&(r.indent.adjustMultilineComment=!1),r}(r,t),t.sourceMaps?new n.default(t,r):null),this.ast=void 0,this.ast=e}generate(){return super.generate(this.ast)}}t.CodeGenerator=class{constructor(e,t,r){this._generator=void 0,this._generator=new i(e,t,r)}generate(){return this._generator.generate()}}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function({node:e,parent:t,scope:r,id:s},c=!1){if(e.id)return;if(!i.isObjectProperty(t)&&!i.isObjectMethod(t,{kind:"method"})||t.computed&&!i.isLiteral(t.key)){if(i.isVariableDeclarator(t)){if(s=t.id,i.isIdentifier(s)&&!c){const t=r.parent.getBinding(s.name);if(t&&t.constant&&r.getBinding(s.name)===t)return e.id=i.cloneNode(s),void(e.id[i.NOT_LOCAL_BINDING]=!0)}}else if(i.isAssignmentExpression(t,{operator:"="}))s=t.left;else if(!s)return}else s=t.key;let u;return s&&i.isLiteral(s)?u=function(e){return i.isNullLiteral(e)?"null":i.isRegExpLiteral(e)?`_${e.pattern}_${e.flags}`:i.isTemplateLiteral(e)?e.quasis.map((e=>e.value.raw)).join(""):void 0!==e.value?e.value+"":""}(s):s&&i.isIdentifier(s)&&(u=s.name),void 0!==u?(u=i.toBindingIdentifierName(u),(s=i.identifier(u))[i.NOT_LOCAL_BINDING]=!0,function(e,t,r,s){if(e.selfReference){if(!s.hasBinding(r.name)||s.hasGlobal(r.name)){if(!i.isFunction(t))return;let e=o;t.generator&&(e=a);const l=e({FUNCTION:t,FUNCTION_ID:r,FUNCTION_KEY:s.generateUidIdentifier(r.name)}).expression,c=l.callee.body.body[0].params;for(let e=0,r=(0,n.default)(t);e{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.merge=function(e,t){const{placeholderWhitelist:r=e.placeholderWhitelist,placeholderPattern:n=e.placeholderPattern,preserveComments:s=e.preserveComments,syntacticPlaceholders:i=e.syntacticPlaceholders}=t;return{parser:Object.assign({},e.parser,t.parser),placeholderWhitelist:r,placeholderPattern:n,preserveComments:s,syntacticPlaceholders:i}},t.validate=function(e){if(null!=e&&"object"!=typeof e)throw new Error("Unknown template options.");const t=e||{},{placeholderWhitelist:r,placeholderPattern:n,preserveComments:s,syntacticPlaceholders:i}=t,o=function(e,t){if(null==e)return{};var r,n,s={},i=Object.keys(e);for(n=0;n=0||(s[r]=e[r]);return s}(t,["placeholderWhitelist","placeholderPattern","preserveComments","syntacticPlaceholders"]);if(null!=r&&!(r instanceof Set))throw new Error("'.placeholderWhitelist' must be a Set, null, or undefined");if(null!=n&&!(n instanceof RegExp)&&!1!==n)throw new Error("'.placeholderPattern' must be a RegExp, false, null, or undefined");if(null!=s&&"boolean"!=typeof s)throw new Error("'.preserveComments' must be a boolean, null, or undefined");if(null!=i&&"boolean"!=typeof i)throw new Error("'.syntacticPlaceholders' must be a boolean, null, or undefined");if(!0===i&&(null!=r||null!=n))throw new Error("'.placeholderWhitelist' and '.placeholderPattern' aren't compatible with '.syntacticPlaceholders: true'");return{parser:o,placeholderWhitelist:r||void 0,placeholderPattern:null==n?void 0:n,preserveComments:null==s?void 0:s,syntacticPlaceholders:null==i?void 0:i}},t.normalizeReplacements=function(e){if(Array.isArray(e))return e.reduce(((e,t,r)=>(e["$"+r]=t,e)),{});if("object"==typeof e||null==e)return e||void 0;throw new Error("Template replacements must be an array, object, null, or undefined")}},e=>{var t=Object.prototype.hasOwnProperty,r=Object.prototype.toString;e.exports=function(e,n,s){if("[object Function]"!==r.call(n))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var o=0;o{"use strict";var n=["BigInt64Array","BigUint64Array","Float32Array","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Uint8Array","Uint8ClampedArray"];e.exports=function(){for(var e=[],t=0;t{"use strict";var n=r(67)("%Object.getOwnPropertyDescriptor%");if(n)try{n([],"length")}catch(e){n=null}e.exports=n},(e,t,r)=>{"use strict";var n=r(136),s=r(137),i=r(66),o=i("Object.prototype.toString"),a=r(68)()&&"symbol"==typeof Symbol.toStringTag,l=s(),c=i("Array.prototype.indexOf",!0)||function(e,t){for(var r=0;r-1}return!!f&&function(e){var t=!1;return n(p,(function(r,n){if(!t)try{t=r.call(e)===n}catch(e){}})),t}(e)}},(e,t,r)=>{"use strict";var n=r(40),s=r(51),i=r(142),o=r(143),a=r(253),l=s(o(),Object);n(l,{getPolyfill:o,implementation:i,shim:a}),e.exports=l},e=>{"use strict";var t=Object.prototype.toString;e.exports=function(e){var r=t.call(e),n="[object Arguments]"===r;return n||(n="[object Array]"!==r&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===t.call(e.callee)),n}},e=>{"use strict";var t=function(e){return e!=e};e.exports=function(e,r){return 0===e&&0===r?1/e==1/r:e===r||!(!t(e)||!t(r))}},(e,t,r)=>{"use strict";var n=r(142);e.exports=function(){return"function"==typeof Object.is?Object.is:n}},e=>{"use strict";e.exports=function(e){return e!=e}},(e,t,r)=>{"use strict";var n=r(144);e.exports=function(){return Number.isNaN&&Number.isNaN(NaN)&&!Number.isNaN("a")?Number.isNaN:n}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addDefault=function(e,t,r){return new n.default(e).addDefault(t,r)},t.addNamed=function(e,t,r,s){return new n.default(e).addNamed(t,r,s)},t.addNamespace=function(e,t,r){return new n.default(e).addNamespace(t,r)},t.addSideEffect=function(e,t,r){return new n.default(e).addSideEffect(t,r)},Object.defineProperty(t,"ImportInjector",{enumerable:!0,get:function(){return n.default}}),Object.defineProperty(t,"isModule",{enumerable:!0,get:function(){return s.default}});var n=r(459),s=r(257)},(e,t,r)=>{const n=r(12);e.exports=(e,t,r)=>0!==n(e,t,r)},(e,t,r)=>{const n=r(71),s=r(147),i=r(44),o=r(74),a=r(73),l=r(75);e.exports=(e,t,r,c)=>{switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return n(e,r,c);case"!=":return s(e,r,c);case">":return i(e,r,c);case">=":return o(e,r,c);case"<":return a(e,r,c);case"<=":return l(e,r,c);default:throw new TypeError(`Invalid operator: ${t}`)}}},(e,t,r)=>{"use strict";const n=r(274),s=Symbol("max"),i=Symbol("length"),o=Symbol("lengthCalculator"),a=Symbol("allowStale"),l=Symbol("maxAge"),c=Symbol("dispose"),u=Symbol("noDisposeOnSet"),p=Symbol("lruList"),f=Symbol("cache"),d=Symbol("updateAgeOnGet"),h=()=>1,m=(e,t,r)=>{const n=e[f].get(t);if(n){const t=n.value;if(y(e,t)){if(b(e,n),!e[a])return}else r&&(e[d]&&(n.value.now=Date.now()),e[p].unshiftNode(n));return t.value}},y=(e,t)=>{if(!t||!t.maxAge&&!e[l])return!1;const r=Date.now()-t.now;return t.maxAge?r>t.maxAge:e[l]&&r>e[l]},g=e=>{if(e[i]>e[s])for(let t=e[p].tail;e[i]>e[s]&&null!==t;){const r=t.prev;b(e,t),t=r}},b=(e,t)=>{if(t){const r=t.value;e[c]&&e[c](r.key,r.value),e[i]-=r.length,e[f].delete(r.key),e[p].removeNode(t)}};class v{constructor(e,t,r,n,s){this.key=e,this.value=t,this.length=r,this.now=n,this.maxAge=s||0}}const E=(e,t,r,n)=>{let s=r.value;y(e,s)&&(b(e,r),e[a]||(s=void 0)),s&&t.call(n,s.value,s.key,e)};e.exports=class{constructor(e){if("number"==typeof e&&(e={max:e}),e||(e={}),e.max&&("number"!=typeof e.max||e.max<0))throw new TypeError("max must be a non-negative number");this[s]=e.max||1/0;const t=e.length||h;if(this[o]="function"!=typeof t?h:t,this[a]=e.stale||!1,e.maxAge&&"number"!=typeof e.maxAge)throw new TypeError("maxAge must be a number");this[l]=e.maxAge||0,this[c]=e.dispose,this[u]=e.noDisposeOnSet||!1,this[d]=e.updateAgeOnGet||!1,this.reset()}set max(e){if("number"!=typeof e||e<0)throw new TypeError("max must be a non-negative number");this[s]=e||1/0,g(this)}get max(){return this[s]}set allowStale(e){this[a]=!!e}get allowStale(){return this[a]}set maxAge(e){if("number"!=typeof e)throw new TypeError("maxAge must be a non-negative number");this[l]=e,g(this)}get maxAge(){return this[l]}set lengthCalculator(e){"function"!=typeof e&&(e=h),e!==this[o]&&(this[o]=e,this[i]=0,this[p].forEach((e=>{e.length=this[o](e.value,e.key),this[i]+=e.length}))),g(this)}get lengthCalculator(){return this[o]}get length(){return this[i]}get itemCount(){return this[p].length}rforEach(e,t){t=t||this;for(let r=this[p].tail;null!==r;){const n=r.prev;E(this,e,r,t),r=n}}forEach(e,t){t=t||this;for(let r=this[p].head;null!==r;){const n=r.next;E(this,e,r,t),r=n}}keys(){return this[p].toArray().map((e=>e.key))}values(){return this[p].toArray().map((e=>e.value))}reset(){this[c]&&this[p]&&this[p].length&&this[p].forEach((e=>this[c](e.key,e.value))),this[f]=new Map,this[p]=new n,this[i]=0}dump(){return this[p].map((e=>!y(this,e)&&{k:e.key,v:e.value,e:e.now+(e.maxAge||0)})).toArray().filter((e=>e))}dumpLru(){return this[p]}set(e,t,r){if((r=r||this[l])&&"number"!=typeof r)throw new TypeError("maxAge must be a number");const n=r?Date.now():0,a=this[o](t,e);if(this[f].has(e)){if(a>this[s])return b(this,this[f].get(e)),!1;const o=this[f].get(e).value;return this[c]&&(this[u]||this[c](e,o.value)),o.now=n,o.maxAge=r,o.value=t,this[i]+=a-o.length,o.length=a,this.get(e),g(this),!0}const d=new v(e,t,a,n,r);return d.length>this[s]?(this[c]&&this[c](e,t),!1):(this[i]+=d.length,this[p].unshift(d),this[f].set(e,this[p].head),g(this),!0)}has(e){if(!this[f].has(e))return!1;const t=this[f].get(e).value;return!y(this,t)}get(e){return m(this,e,!0)}peek(e){return m(this,e,!1)}pop(){const e=this[p].tail;return e?(b(this,e),e.value):null}del(e){b(this,this[f].get(e))}load(e){this.reset();const t=Date.now();for(let r=e.length-1;r>=0;r--){const n=e[r],s=n.e||0;if(0===s)this.set(n.k,n.v);else{const e=s-t;e>0&&this.set(n.k,n.v,e)}}}prune(){this[f].forEach(((e,t)=>m(this,t,!1)))}}},(e,t)=>{"use strict";function r(e,t){for(const r of Object.keys(t)){const n=t[r];void 0!==n&&(e[r]=n)}}Object.defineProperty(t,"__esModule",{value:!0}),t.mergeOptions=function(e,t){for(const n of Object.keys(t))if("parserOpts"!==n&&"generatorOpts"!==n&&"assumptions"!==n||!t[n]){const r=t[n];void 0!==r&&(e[n]=r)}else{const s=t[n];r(e[n]||(e[n]={}),s)}},t.isIterableIterator=function(e){return!!e&&"function"==typeof e.next&&"function"==typeof e[Symbol.iterator]}},e=>{function t(e){this.name="BrowserslistError",this.message=e,this.browserslist=!0,Error.captureStackTrace&&Error.captureStackTrace(this,t)}t.prototype=Error.prototype,e.exports=t},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.semverMin=l,t.semverify=function(e){if("string"==typeof e&&n.valid(e))return e;a.invariant("number"==typeof e||"string"==typeof e&&o.test(e),`'${e}' is not a valid version`);const t=e.toString().split(".");for(;t.length<3;)t.push("0");return t.join(".")},t.isUnreleasedVersion=function(e,t){const r=i.unreleasedLabels[t];return!!r&&r===e.toString().toLowerCase()},t.getLowestUnreleased=c,t.getHighestUnreleased=function(e,t,r){return c(e,t,r)===e?t:e},t.getLowestImplementedVersion=function(e,t){const r=e[t];return r||"android"!==t?r:e.chrome};var n=r(28),s=r(297),i=r(153);const o=/^(\d+|\d+.\d+)$/,a=new s.OptionValidator("@babel/helper-compilation-targets");function l(e,t){return e&&n.lt(e,t)?e:t}function c(e,t,r){const n=i.unreleasedLabels[r],s=[e,t].some((e=>e===n));return s?e===s?t:e||t:l(e,t)}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.browserNameMap=t.unreleasedLabels=void 0,t.unreleasedLabels={safari:"tp"},t.browserNameMap={and_chr:"chrome",and_ff:"firefox",android:"android",chrome:"chrome",edge:"edge",firefox:"firefox",ie:"ie",ie_mob:"ie",ios_saf:"ios",node:"node",op_mob:"opera",opera:"opera",safari:"safari",samsung:"samsung"}},e=>{"use strict";e.exports.isClean=Symbol("isClean"),e.exports.my=Symbol("my")},e=>{"use strict";const t={colon:": ",indent:" ",beforeDecl:"\n",beforeRule:"\n",beforeOpen:" ",beforeClose:"\n",beforeComment:"\n",after:"\n",emptyBody:"",commentLeft:" ",commentRight:" ",semicolon:!1};e.exports=class{constructor(e){this.builder=e}stringify(e,t){if(!this[e.type])throw new Error("Unknown AST node type "+e.type+". Maybe you need to change PostCSS stringifier.");this[e.type](e,t)}document(e){this.body(e)}root(e){this.body(e),e.raws.after&&this.builder(e.raws.after)}comment(e){let t=this.raw(e,"left","commentLeft"),r=this.raw(e,"right","commentRight");this.builder("/*"+t+e.text+r+"*/",e)}decl(e,t){let r=this.raw(e,"between","colon"),n=e.prop+r+this.rawValue(e,"value");e.important&&(n+=e.raws.important||" !important"),t&&(n+=";"),this.builder(n,e)}rule(e){this.block(e,this.rawValue(e,"selector")),e.raws.ownSemicolon&&this.builder(e.raws.ownSemicolon,e,"end")}atrule(e,t){let r="@"+e.name,n=e.params?this.rawValue(e,"params"):"";if(void 0!==e.raws.afterName?r+=e.raws.afterName:n&&(r+=" "),e.nodes)this.block(e,r+n);else{let s=(e.raws.between||"")+(t?";":"");this.builder(r+n+s,e)}}body(e){let t=e.nodes.length-1;for(;t>0&&"comment"===e.nodes[t].type;)t-=1;let r=this.raw(e,"semicolon");for(let n=0;n{if(s=e.raws[r],void 0!==s)return!1}))}var a;return void 0===s&&(s=t[n]),o.rawCache[n]=s,s}rawSemicolon(e){let t;return e.walk((e=>{if(e.nodes&&e.nodes.length&&"decl"===e.last.type&&(t=e.raws.semicolon,void 0!==t))return!1})),t}rawEmptyBody(e){let t;return e.walk((e=>{if(e.nodes&&0===e.nodes.length&&(t=e.raws.after,void 0!==t))return!1})),t}rawIndent(e){if(e.raws.indent)return e.raws.indent;let t;return e.walk((r=>{let n=r.parent;if(n&&n!==e&&n.parent&&n.parent===e&&void 0!==r.raws.before){let e=r.raws.before.split("\n");return t=e[e.length-1],t=t.replace(/\S/g,""),!1}})),t}rawBeforeComment(e,t){let r;return e.walkComments((e=>{if(void 0!==e.raws.before)return r=e.raws.before,r.includes("\n")&&(r=r.replace(/[^\n]+$/,"")),!1})),void 0===r?r=this.raw(t,null,"beforeDecl"):r&&(r=r.replace(/\S/g,"")),r}rawBeforeDecl(e,t){let r;return e.walkDecls((e=>{if(void 0!==e.raws.before)return r=e.raws.before,r.includes("\n")&&(r=r.replace(/[^\n]+$/,"")),!1})),void 0===r?r=this.raw(t,null,"beforeRule"):r&&(r=r.replace(/\S/g,"")),r}rawBeforeRule(e){let t;return e.walk((r=>{if(r.nodes&&(r.parent!==e||e.first!==r)&&void 0!==r.raws.before)return t=r.raws.before,t.includes("\n")&&(t=t.replace(/[^\n]+$/,"")),!1})),t&&(t=t.replace(/\S/g,"")),t}rawBeforeClose(e){let t;return e.walk((e=>{if(e.nodes&&e.nodes.length>0&&void 0!==e.raws.after)return t=e.raws.after,t.includes("\n")&&(t=t.replace(/[^\n]+$/,"")),!1})),t&&(t=t.replace(/\S/g,"")),t}rawBeforeOpen(e){let t;return e.walk((e=>{if("decl"!==e.type&&(t=e.raws.between,void 0!==t))return!1})),t}rawColon(e){let t;return e.walkDecls((e=>{if(void 0!==e.raws.between)return t=e.raws.between.replace(/[^\s:]/g,""),!1})),t}beforeAfter(e,t){let r;r="decl"===e.type?this.raw(e,null,"beforeDecl"):"comment"===e.type?this.raw(e,null,"beforeComment"):"before"===t?this.raw(e,null,"beforeRule"):this.raw(e,null,"beforeClose");let n=e.parent,s=0;for(;n&&"root"!==n.type;)s+=1,n=n.parent;if(r.includes("\n")){let t=this.raw(e,null,"indent");if(t.length)for(let e=0;e{"use strict";let{isClean:n,my:s}=r(154),i=r(320),o=r(86),a=r(22),l=r(87),c=(r(322),r(159)),u=r(161),p=r(35);const f={document:"Document",root:"Root",atrule:"AtRule",rule:"Rule",decl:"Declaration",comment:"Comment"},d={postcssPlugin:!0,prepare:!0,Once:!0,Document:!0,Root:!0,Declaration:!0,Rule:!0,AtRule:!0,Comment:!0,DeclarationExit:!0,RuleExit:!0,AtRuleExit:!0,CommentExit:!0,RootExit:!0,DocumentExit:!0,OnceExit:!0},h={postcssPlugin:!0,prepare:!0,Once:!0};function m(e){return"object"==typeof e&&"function"==typeof e.then}function y(e){let t=!1,r=f[e.type];return"decl"===e.type?t=e.prop.toLowerCase():"atrule"===e.type&&(t=e.name.toLowerCase()),t&&e.append?[r,r+"-"+t,0,r+"Exit",r+"Exit-"+t]:t?[r,r+"-"+t,r+"Exit",r+"Exit-"+t]:e.append?[r,0,r+"Exit"]:[r,r+"Exit"]}function g(e){let t;return t="document"===e.type?["Document",0,"DocumentExit"]:"root"===e.type?["Root",0,"RootExit"]:y(e),{node:e,events:t,eventIndex:0,visitors:[],visitorIndex:0,iterator:0}}function b(e){return e[n]=!1,e.nodes&&e.nodes.forEach((e=>b(e))),e}let v={};class E{constructor(e,t,r){let n;if(this.stringified=!1,this.processed=!1,"object"!=typeof t||null===t||"root"!==t.type&&"document"!==t.type)if(t instanceof E||t instanceof c)n=b(t.root),t.map&&(void 0===r.map&&(r.map={}),r.map.inline||(r.map.inline=!1),r.map.prev=t.map);else{let e=u;r.syntax&&(e=r.syntax.parse),r.parser&&(e=r.parser),e.parse&&(e=e.parse);try{n=e(t,r)}catch(e){this.processed=!0,this.error=e}n&&!n[s]&&a.rebuild(n)}else n=b(t);this.result=new c(e,n,r),this.helpers={...v,result:this.result,postcss:v},this.plugins=this.processor.plugins.map((e=>"object"==typeof e&&e.prepare?{...e,...e.prepare(this.result)}:e))}get[Symbol.toStringTag](){return"LazyResult"}get processor(){return this.result.processor}get opts(){return this.result.opts}get css(){return this.stringify().css}get content(){return this.stringify().content}get map(){return this.stringify().map}get root(){return this.sync().root}get messages(){return this.sync().messages}warnings(){return this.sync().warnings()}toString(){return this.css}then(e,t){return this.async().then(e,t)}catch(e){return this.async().catch(e)}finally(e){return this.async().then(e,e)}async(){return this.error?Promise.reject(this.error):this.processed?Promise.resolve(this.result):(this.processing||(this.processing=this.runAsync()),this.processing)}sync(){if(this.error)throw this.error;if(this.processed)return this.result;if(this.processed=!0,this.processing)throw this.getAsyncError();for(let e of this.plugins)if(m(this.runOnRoot(e)))throw this.getAsyncError();if(this.prepareVisitors(),this.hasListener){let e=this.result.root;for(;!e[n];)e[n]=!0,this.walkSync(e);if(this.listeners.OnceExit)if("document"===e.type)for(let t of e.nodes)this.visitSync(this.listeners.OnceExit,t);else this.visitSync(this.listeners.OnceExit,e)}return this.result}stringify(){if(this.error)throw this.error;if(this.stringified)return this.result;this.stringified=!0,this.sync();let e=this.result.opts,t=o;e.syntax&&(t=e.syntax.stringify),e.stringifier&&(t=e.stringifier),t.stringify&&(t=t.stringify);let r=new i(t,this.result.root,this.result.opts).generate();return this.result.css=r[0],this.result.map=r[1],this.result}walkSync(e){e[n]=!0;let t=y(e);for(let r of t)if(0===r)e.nodes&&e.each((e=>{e[n]||this.walkSync(e)}));else{let t=this.listeners[r];if(t&&this.visitSync(t,e.toProxy()))return}}visitSync(e,t){for(let[r,n]of e){let e;this.result.lastPlugin=r;try{e=n(t,this.helpers)}catch(e){throw this.handleError(e,t.proxyOf)}if("root"!==t.type&&"document"!==t.type&&!t.parent)return!0;if(m(e))throw this.getAsyncError()}}runOnRoot(e){this.result.lastPlugin=e;try{if("object"==typeof e&&e.Once){if("document"===this.result.root.type){let t=this.result.root.nodes.map((t=>e.Once(t,this.helpers)));return m(t[0])?Promise.all(t):t}return e.Once(this.result.root,this.helpers)}if("function"==typeof e)return e(this.result.root,this.result)}catch(e){throw this.handleError(e)}}getAsyncError(){throw new Error("Use process(css).then(cb) to work with async plugins")}handleError(e,t){let r=this.result.lastPlugin;try{t&&t.addToError(e),this.error=e,"CssSyntaxError"!==e.name||e.plugin?r.postcssVersion:(e.plugin=r.postcssPlugin,e.setMessage())}catch(e){console&&console.error}return e}async runAsync(){this.plugin=0;for(let e=0;e0;){let e=this.visitTick(t);if(m(e))try{await e}catch(e){let r=t[t.length-1].node;throw this.handleError(e,r)}}}if(this.listeners.OnceExit)for(let[t,r]of this.listeners.OnceExit){this.result.lastPlugin=t;try{if("document"===e.type){let t=e.nodes.map((e=>r(e,this.helpers)));await Promise.all(t)}else await r(e,this.helpers)}catch(e){throw this.handleError(e)}}}return this.processed=!0,this.stringify()}prepareVisitors(){this.listeners={};let e=(e,t,r)=>{this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push([e,r])};for(let t of this.plugins)if("object"==typeof t)for(let r in t){if(!d[r]&&/^[A-Z]/.test(r))throw new Error(`Unknown event ${r} in ${t.postcssPlugin}. Try to update PostCSS (${this.processor.version} now).`);if(!h[r])if("object"==typeof t[r])for(let n in t[r])e(t,"*"===n?r:r+"-"+n.toLowerCase(),t[r][n]);else"function"==typeof t[r]&&e(t,r,t[r])}this.hasListener=Object.keys(this.listeners).length>0}visitTick(e){let t=e[e.length-1],{node:r,visitors:s}=t;if("root"!==r.type&&"document"!==r.type&&!r.parent)return void e.pop();if(s.length>0&&t.visitorIndex{v=e},e.exports=E,E.default=E,p.registerLazyResult(E),l.registerLazyResult(E)},()=>{},()=>{},(e,t,r)=>{"use strict";let n=r(160);class s{constructor(e,t,r){this.processor=e,this.messages=[],this.root=t,this.opts=r,this.css=void 0,this.map=void 0}toString(){return this.css}warn(e,t={}){t.plugin||this.lastPlugin&&this.lastPlugin.postcssPlugin&&(t.plugin=this.lastPlugin.postcssPlugin);let r=new n(e,t);return this.messages.push(r),r}warnings(){return this.messages.filter((e=>"warning"===e.type))}get content(){return this.css}}e.exports=s,s.default=s},e=>{"use strict";class t{constructor(e,t={}){if(this.type="warning",this.text=e,t.node&&t.node.source){let e=t.node.positionBy(t);this.line=e.line,this.column=e.column}for(let e in t)this[e]=t[e]}toString(){return this.node?this.node.error(this.text,{plugin:this.plugin,index:this.index,word:this.word}).message:this.plugin?this.plugin+": "+this.text:this.text}}e.exports=t,t.default=t},(e,t,r)=>{"use strict";let n=r(22),s=r(323),i=r(90);function o(e,t){let r=new i(e,t),n=new s(r);try{n.parse()}catch(e){throw e}return n.root}e.exports=o,o.default=o,n.registerParse(o)},e=>{"use strict";let t={split(e,t,r){let n=[],s="",i=!1,o=0,a=!1,l=!1;for(let r of e)l?l=!1:"\\"===r?l=!0:a?r===a&&(a=!1):'"'===r||"'"===r?a=r:"("===r?o+=1:")"===r?o>0&&(o-=1):0===o&&t.includes(r)&&(i=!0),i?(""!==s&&n.push(s.trim()),s="",i=!1):s+=r;return(r||""!==s)&&n.push(s.trim()),n},space:e=>t.split(e,[" ","\n","\t"]),comma:e=>t.split(e,[","],!0)};e.exports=t,t.default=t},(e,t,r)=>{"use strict";var n=r(37).Buffer;let{SourceMapConsumer:s,SourceMapGenerator:i}=r(157),{existsSync:o,readFileSync:a}=r(514),{dirname:l,join:c}=r(158);class u{constructor(e,t){if(!1===t.map)return;this.loadAnnotation(e),this.inline=this.startWith(this.annotation,"data:");let r=t.map?t.map.prev:void 0,n=this.loadMap(t.from,r);!this.mapFile&&t.from&&(this.mapFile=t.from),this.mapFile&&(this.root=l(this.mapFile)),n&&(this.text=n)}consumer(){return this.consumerCache||(this.consumerCache=new s(this.text)),this.consumerCache}withContent(){return!!(this.consumer().sourcesContent&&this.consumer().sourcesContent.length>0)}startWith(e,t){return!!e&&e.substr(0,t.length)===t}getAnnotationURL(e){return e.match(/\/\*\s*# sourceMappingURL=((?:(?!sourceMappingURL=).)*)\*\//)[1].trim()}loadAnnotation(e){let t=e.match(/\/\*\s*# sourceMappingURL=(?:(?!sourceMappingURL=).)*\*\//gm);if(t&&t.length>0){let e=t[t.length-1];e&&(this.annotation=this.getAnnotationURL(e))}}decodeInline(e){if(/^data:application\/json;charset=utf-?8,/.test(e)||/^data:application\/json,/.test(e))return decodeURIComponent(e.substr(RegExp.lastMatch.length));if(/^data:application\/json;charset=utf-?8;base64,/.test(e)||/^data:application\/json;base64,/.test(e))return t=e.substr(RegExp.lastMatch.length),n?n.from(t,"base64").toString():window.atob(t);var t;let r=e.match(/data:application\/json;([^,]+),/)[1];throw new Error("Unsupported source map encoding "+r)}loadFile(e){if(this.root=l(e),o(e))return this.mapFile=e,a(e,"utf-8").toString().trim()}loadMap(e,t){if(!1===t)return!1;if(t){if("string"==typeof t)return t;if("function"!=typeof t){if(t instanceof s)return i.fromSourceMap(t).toString();if(t instanceof i)return t.toString();if(this.isMap(t))return JSON.stringify(t);throw new Error("Unsupported previous source map format: "+t.toString())}{let r=t(e);if(r){let e=this.loadFile(r);if(!e)throw new Error("Unable to load previous source map: "+r.toString());return e}}}else{if(this.inline)return this.decodeInline(this.annotation);if(this.annotation){let t=this.annotation;return e&&(t=c(l(e),t)),this.loadFile(t)}}}isMap(e){return"object"==typeof e&&("string"==typeof e.mappings||"string"==typeof e._mappings||Array.isArray(e.sections))}}e.exports=u,u.default=u},e=>{const t=/[$]?[\w-]+/g;e.exports=(e,r)=>{let n;for(;n=t.exec(e);){const s=r[n[0]];s&&(e=e.slice(0,n.index)+s+e.slice(t.lastIndex),t.lastIndex-=n[0].length-s.length)}return e}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(422);Object.keys(n).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===n[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return n[e]}}))}));var s=r(423);Object.keys(s).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===s[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return s[e]}}))}));var i=r(424);Object.keys(i).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===i[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return i[e]}}))}));var o=r(425);Object.keys(o).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===o[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return o[e]}}))}));var a=r(426);Object.keys(a).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===a[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))}));var l=r(234);Object.keys(l).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===l[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return l[e]}}))}));var c=r(235);Object.keys(c).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===c[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return c[e]}}))}));var u=r(429);Object.keys(u).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===u[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return u[e]}}))}));var p=r(430);Object.keys(p).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===p[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return p[e]}}))}));var f=r(431);Object.keys(f).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===f[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return f[e]}}))}));var d=r(432);Object.keys(d).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===d[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return d[e]}}))}))},(e,t,r)=>{"use strict";t.__esModule=!0;var n=r(5);Object.keys(n).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===n[e]||(t[e]=n[e]))}));var s=r(516);Object.keys(s).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===s[e]||(t[e]=s[e]))}));var i=r(517);Object.keys(i).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===i[e]||(t[e]=i[e]))}))},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const a=i(r(0)),l=r(146),c=r(50),u=o(r(169)),p=/^xlink([A-Z])/,f=(e,t)=>{const r=((e,t)=>e.map((e=>{if(e.isJSXText()){const r=c.transformJSXText(e);return r?a.callExpression(c.createIdentifier(t,"createTextVNode"),[r]):r}if(e.isJSXExpressionContainer()){const t=c.transformJSXExpressionContainer(e);if(a.isIdentifier(t)){const{name:r}=t,{referencePaths:n=[]}=e.scope.getBinding(r)||{};n.forEach((e=>{c.walksScope(e,r,2)}))}return t}if(a.isJSXSpreadChild(e))return c.transformJSXSpreadChild(e);if(e.isCallExpression())return e.node;if(e.isJSXElement())return f(e,t);throw new Error(`getChildren: ${e.type} is not supported`)})).filter((e=>null!=e&&!a.isJSXEmptyExpression(e))))(e.get("children"),t),{tag:n,props:s,isComponent:i,directives:o,patchFlag:d,dynamicPropNames:h,slots:m}=((e,t)=>{const r=c.getTag(e,t),n=c.checkIsComponent(e.get("openingElement")),s=e.get("openingElement").get("attributes"),i=[],o=new Set;let d=null,h=0;if(0===s.length)return{tag:r,isComponent:n,slots:d,props:a.nullLiteral(),directives:i,patchFlag:h,dynamicPropNames:o};let m=[],y=!1,g=!1,b=!1,v=!1,E=!1;const x=[],{mergeProps:S=!0}=t.opts;s.forEach((s=>{if(s.isJSXAttribute()){let h=c.getJSXAttributeName(s);const S=((e,t)=>{const r=e.get("value");return r.isJSXElement()?f(r,t):r.isStringLiteral()?r.node:r.isJSXExpressionContainer()?c.transformJSXExpressionContainer(r):null})(s,t);if(c.isConstant(S)&&"ref"!==h||(!n&&c.isOn(h)&&"onclick"!==h.toLowerCase()&&"onUpdate:modelValue"!==h&&(v=!0),"ref"===h?y=!0:"class"!==h||n?"style"!==h||n?"key"===h||c.isDirective(h)||"on"===h||o.add(h):b=!0:g=!0),t.opts.transformOn&&("on"===h||"nativeOn"===h))return t.get("transformOn")||t.set("transformOn",l.addDefault(e,"@vue/babel-helper-vue-transform-on",{nameHint:"_transformOn"})),void x.push(a.callExpression(t.get("transformOn"),[S||a.booleanLiteral(!0)]));if(c.isDirective(h)){const{directive:e,modifiers:l,values:c,args:p,directiveName:f}=u.default({tag:r,isComponent:n,name:h,path:s,state:t,value:S});if("slots"===f)return void(d=S);e?i.push(a.arrayExpression(e)):"html"===f?(m.push(a.objectProperty(a.stringLiteral("innerHTML"),c[0])),o.add("innerHTML")):"text"===f&&(m.push(a.objectProperty(a.stringLiteral("textContent"),c[0])),o.add("textContent")),["models","model"].includes(f)&&c.forEach(((t,r)=>{var n,s,i,c;const u=p[r],f=u&&!a.isStringLiteral(u)&&!a.isNullLiteral(u);e||(m.push(a.objectProperty(a.isNullLiteral(u)?a.stringLiteral("modelValue"):u,t,f)),f||o.add((null===(n=u)||void 0===n?void 0:n.value)||"modelValue"),(null===(s=l[r])||void 0===s?void 0:s.size)&&m.push(a.objectProperty(f?a.binaryExpression("+",u,a.stringLiteral("Modifiers")):a.stringLiteral(`${(null===(i=u)||void 0===i?void 0:i.value)||"model"}Modifiers`),a.objectExpression([...l[r]].map((e=>a.objectProperty(a.stringLiteral(e),a.booleanLiteral(!0))))),f)));const d=f?a.binaryExpression("+",a.stringLiteral("onUpdate"),u):a.stringLiteral(`onUpdate:${(null===(c=u)||void 0===c?void 0:c.value)||"modelValue"}`);m.push(a.objectProperty(d,a.arrowFunctionExpression([a.identifier("$event")],a.assignmentExpression("=",t,a.identifier("$event"))),f)),f?E=!0:o.add(d.value)}))}else h.match(p)&&(h=h.replace(p,((e,t)=>`xlink:${t.toLowerCase()}`))),m.push(a.objectProperty(a.stringLiteral(h),S||a.booleanLiteral(!0)))}else m.length&&S&&(x.push(a.objectExpression(c.dedupeProperties(m,S))),m=[]),E=!0,c.transformJSXSpreadAttribute(e,s,S,S?x:m)})),E?h|=16:(g&&(h|=2),b&&(h|=4),o.size&&(h|=8),v&&(h|=32)),0!==h&&32!==h||!(y||i.length>0)||(h|=512);let T=a.nullLiteral();return x.length?(m.length&&x.push(a.objectExpression(c.dedupeProperties(m,S))),T=x.length>1?a.callExpression(c.createIdentifier(t,"mergeProps"),x):x[0]):m.length&&(T=1===m.length&&a.isSpreadElement(m[0])?m[0].argument:a.objectExpression(c.dedupeProperties(m,S))),{tag:r,props:T,isComponent:n,slots:d,directives:i,patchFlag:h,dynamicPropNames:o}})(e,t),{optimize:y=!1}=t.opts,g=e.getData("slotFlag")||1;let b;if(r.length>1||m)b=i?r.length?a.objectExpression([!!r.length&&a.objectProperty(a.identifier("default"),a.arrowFunctionExpression([],a.arrayExpression(c.buildIIFE(e,r)))),...m?a.isObjectExpression(m)?m.properties:[a.spreadElement(m)]:[],y&&a.objectProperty(a.identifier("_"),a.numericLiteral(g))].filter(Boolean)):m:a.arrayExpression(r);else if(1===r.length){const{enableObjectSlots:n=!0}=t.opts,s=r[0],o=a.objectExpression([a.objectProperty(a.identifier("default"),a.arrowFunctionExpression([],a.arrayExpression(c.buildIIFE(e,[s])))),y&&a.objectProperty(a.identifier("_"),a.numericLiteral(g))].filter(Boolean));if(a.isIdentifier(s)&&i)b=n?a.conditionalExpression(a.callExpression(t.get("@vue/babel-plugin-jsx/runtimeIsSlot")(),[s]),s,o):o;else if(a.isCallExpression(s)&&s.loc&&i)if(n){const{scope:r}=e,n=r.generateUidIdentifier("slot");r&&r.push({id:n,kind:"let"});const i=a.objectExpression([a.objectProperty(a.identifier("default"),a.arrowFunctionExpression([],a.arrayExpression(c.buildIIFE(e,[n])))),y&&a.objectProperty(a.identifier("_"),a.numericLiteral(g))].filter(Boolean)),o=a.assignmentExpression("=",n,s),l=a.callExpression(t.get("@vue/babel-plugin-jsx/runtimeIsSlot")(),[o]);b=a.conditionalExpression(l,n,i)}else b=o;else b=a.isFunctionExpression(s)||a.isArrowFunctionExpression(s)?a.objectExpression([a.objectProperty(a.identifier("default"),s)]):a.isObjectExpression(s)?a.objectExpression([...s.properties,y&&a.objectProperty(a.identifier("_"),a.numericLiteral(g))].filter(Boolean)):i?a.objectExpression([a.objectProperty(a.identifier("default"),a.arrowFunctionExpression([],a.arrayExpression([s])))]):a.arrayExpression([s])}const v=a.callExpression(c.createIdentifier(t,"createVNode"),[n,s,b||a.nullLiteral(),!!d&&y&&a.numericLiteral(d),!!h.size&&y&&a.arrayExpression([...h.keys()].map((e=>a.stringLiteral(e))))].filter(Boolean));return o.length?a.callExpression(c.createIdentifier(t,"withDirectives"),[v,a.arrayExpression(o)]):v};t.default={JSXElement:{exit(e,t){e.replaceWith(f(e,t))}}}},function(e,t,r){var n;/*! https://mths.be/punycode v1.3.2 by @mathias */e=r.nmd(e),function(s){t&&t.nodeType,e&&e.nodeType;var i="object"==typeof r.g&&r.g;i.global!==i&&i.window!==i&&i.self;var o,a=2147483647,l=36,c=/^xn--/,u=/[^\x20-\x7E]/,p=/[\x2E\u3002\uFF0E\uFF61]/g,f={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},d=Math.floor,h=String.fromCharCode;function m(e){throw RangeError(f[e])}function y(e,t){for(var r=e.length,n=[];r--;)n[r]=t(e[r]);return n}function g(e,t){var r=e.split("@"),n="";return r.length>1&&(n=r[0]+"@",e=r[1]),n+y((e=e.replace(p,".")).split("."),t).join(".")}function b(e){for(var t,r,n=[],s=0,i=e.length;s=55296&&t<=56319&&s65535&&(t+=h((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+h(e)})).join("")}function E(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,r){var n=0;for(e=r?d(e/700):e>>1,e+=d(e/t);e>455;n+=l)e=d(e/35);return d(n+36*e/(e+38))}function S(e){var t,r,n,s,i,o,c,u,p,f,h,y=[],g=e.length,b=0,E=128,S=72;for((r=e.lastIndexOf("-"))<0&&(r=0),n=0;n=128&&m("not-basic"),y.push(e.charCodeAt(n));for(s=r>0?r+1:0;s=g&&m("invalid-input"),((u=(h=e.charCodeAt(s++))-48<10?h-22:h-65<26?h-65:h-97<26?h-97:l)>=l||u>d((a-b)/o))&&m("overflow"),b+=u*o,!(u<(p=c<=S?1:c>=S+26?26:c-S));c+=l)o>d(a/(f=l-p))&&m("overflow"),o*=f;S=x(b-i,t=y.length+1,0==i),d(b/t)>a-E&&m("overflow"),E+=d(b/t),b%=t,y.splice(b++,0,E)}return v(y)}function T(e){var t,r,n,s,i,o,c,u,p,f,y,g,v,S,T,w=[];for(g=(e=b(e)).length,t=128,r=0,i=72,o=0;o=t&&yd((a-r)/(v=n+1))&&m("overflow"),r+=(c-t)*v,t=c,o=0;oa&&m("overflow"),y==t){for(u=r,p=l;!(u<(f=p<=i?1:p>=i+26?26:p-i));p+=l)T=u-f,S=l-f,w.push(h(E(f+T%S,0))),u=d(T/S);w.push(h(E(u,0))),i=x(r,v,n==s),r=0,++n}++r,++t}return w.join("")}o={version:"1.3.2",ucs2:{decode:b,encode:v},decode:S,encode:T,toASCII:function(e){return g(e,(function(e){return u.test(e)?"xn--"+T(e):e}))},toUnicode:function(e){return g(e,(function(e){return c.test(e)?S(e.slice(4).toLowerCase()):e}))}},void 0===(n=function(){return o}.call(t,r,t,e))||(e.exports=n)}()},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t};Object.defineProperty(t,"__esModule",{value:!0});const o=i(r(0)),a=r(50),l=e=>o.isArrayExpression(e)?e.elements.map((e=>o.isStringLiteral(e)?e.value:"")).filter(Boolean):[],c=(e,t,r,n)=>{var s;if("show"===n)return a.createIdentifier(t,"vShow");if("model"===n){let n;const i=(e=>{const t=e.get("attributes").find((e=>!!o.isJSXAttribute(e)&&o.isJSXIdentifier(e.get("name"))&&"type"===e.get("name").node.name));return t?t.get("value").node:null})(e.parentPath);switch(r.value){case"select":n=a.createIdentifier(t,"vModelSelect");break;case"textarea":n=a.createIdentifier(t,"vModelText");break;default:if(o.isStringLiteral(i)||!i)switch(null===(s=i)||void 0===s?void 0:s.value){case"checkbox":n=a.createIdentifier(t,"vModelCheckbox");break;case"radio":n=a.createIdentifier(t,"vModelRadio");break;default:n=a.createIdentifier(t,"vModelText")}else n=a.createIdentifier(t,"vModelDynamic")}return n}return o.callExpression(a.createIdentifier(t,"resolveDirective"),[o.stringLiteral(n)])};t.default=e=>{var t,r,n;const{name:s,path:i,value:a,state:u,tag:p,isComponent:f}=e,d=[],h=[],m=[],y=s.split("_"),g=(null===(t=y.shift())||void 0===t?void 0:t.replace(/^v/,"").replace(/^-/,"").replace(/^\S/,(e=>e.toLowerCase())))||"",b="models"===g,v="model"===g;if(v&&!o.isJSXExpressionContainer(i.get("value")))throw new Error("You have to use JSX Expression inside your v-model");if(b&&!f)throw new Error("v-models can only use in custom components");const E=!["html","text","model","models"].includes(g)||v&&!f;let x=y;return o.isArrayExpression(a)?(b?a.elements:[a]).forEach((e=>{if(b&&!o.isArrayExpression(e))throw new Error("You should pass a Two-dimensional Arrays to v-models");const{elements:t}=e,[r,n,s]=t;!n||o.isArrayExpression(n)||o.isSpreadElement(n)?o.isArrayExpression(n)?(E||d.push(o.nullLiteral()),x=l(n)):E||d.push(o.nullLiteral()):(d.push(n),x=l(s)),m.push(new Set(x)),h.push(r)})):v&&!E?(d.push(o.nullLiteral()),m.push(new Set(y))):m.push(new Set(y)),{directiveName:g,modifiers:m,values:h.length?h:[a],args:d,directive:E?[c(i,u,p,g),h[0]||a,(null===(r=m[0])||void 0===r?void 0:r.size)?d[0]||o.unaryExpression("void",o.numericLiteral(0),!0):d[0],!!(null===(n=m[0])||void 0===n?void 0:n.size)&&o.objectExpression([...m[0]].map((e=>o.objectProperty(o.identifier(e),o.booleanLiteral(!0)))))].filter(Boolean):void 0}}},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t};Object.defineProperty(t,"__esModule",{value:!0});const o=i(r(0)),a=r(50);t.default={JSXFragment:{enter(e,t){const r=a.createIdentifier(t,a.FRAGMENT);e.replaceWith(((e,t)=>{const r=e.get("children")||[];return o.jsxElement(o.jsxOpeningElement(t,[]),o.jsxClosingElement(t),r.map((({node:e})=>e)),!1)})(e,o.isIdentifier(r)?o.jsxIdentifier(r.name):o.jsxMemberExpression(o.jsxIdentifier(r.object.name),o.jsxIdentifier(r.property.name))))}}}},e=>{"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}}},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s=(n=r(173))&&n.__esModule?n:{default:n},i=function(){function e(e,t){this.func=e||function(){},this.funcRes=null,this.options=t}var t=e.prototype;return t._shouldUpdateSelector=function(e,t){return void 0===t&&(t={}),!1!==Object.assign({},this.options,t).updateSelector&&"string"!=typeof e},t._isLossy=function(e){return void 0===e&&(e={}),!1===Object.assign({},this.options,e).lossless},t._root=function(e,t){return void 0===t&&(t={}),new s.default(e,this._parseOptions(t)).root},t._parseOptions=function(e){return{lossy:this._isLossy(e)}},t._run=function(e,t){var r=this;return void 0===t&&(t={}),new Promise((function(n,s){try{var i=r._root(e,t);Promise.resolve(r.func(i)).then((function(n){var s=void 0;return r._shouldUpdateSelector(e,t)&&(s=i.toString(),e.selector=s),{transform:n,root:i,string:s}})).then(n,s)}catch(e){return void s(e)}}))},t._runSync=function(e,t){void 0===t&&(t={});var r=this._root(e,t),n=this.func(r);if(n&&"function"==typeof n.then)throw new Error("Selector processor returned a promise to a synchronous call.");var s=void 0;return t.updateSelector&&"string"!=typeof e&&(s=r.toString(),e.selector=s),{transform:n,root:r,string:s}},t.ast=function(e,t){return this._run(e,t).then((function(e){return e.root}))},t.astSync=function(e,t){return this._runSync(e,t).root},t.transform=function(e,t){return this._run(e,t).then((function(e){return e.transform}))},t.transformSync=function(e,t){return this._runSync(e,t).transform},t.process=function(e,t){return this._run(e,t).then((function(e){return e.string||e.root.toString()}))},t.processSync=function(e,t){var r=this._runSync(e,t);return r.string||r.root.toString()},e}();t.default=i,e.exports=t.default},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=void 0;var n,s,i=w(r(97)),o=w(r(99)),a=w(r(100)),l=w(r(101)),c=w(r(102)),u=w(r(103)),p=w(r(104)),f=w(r(105)),d=T(r(326)),h=w(r(106)),m=w(r(107)),y=w(r(108)),g=w(r(177)),b=T(r(515)),v=T(r(328)),E=T(r(5)),x=r(91);function S(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return S=function(){return e},e}function T(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=S();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if(Object.prototype.hasOwnProperty.call(e,s)){var i=n?Object.getOwnPropertyDescriptor(e,s):null;i&&(i.get||i.set)?Object.defineProperty(r,s,i):r[s]=e[s]}return r.default=e,t&&t.set(e,r),r}function w(e){return e&&e.__esModule?e:{default:e}}function P(e,t){for(var r=0;rthis.position&&(s=this.parseWhitespaceEquivalentTokens(t)),this.isNamedCombinator()?r=this.namedCombinator():this.currToken[b.FIELDS.TYPE]===v.combinator?(r=new m.default({value:this.content(),source:N(this.currToken),sourceIndex:this.currToken[b.FIELDS.START_POS]}),this.position++):A[this.currToken[b.FIELDS.TYPE]]||s||this.unexpected(),r){if(s){var i=this.convertWhitespaceNodesToSpace(s),o=i.space,a=i.rawSpace;r.spaces.before=o,r.rawSpaceBefore=a}}else{var l=this.convertWhitespaceNodesToSpace(s,!0),c=l.space,u=l.rawSpace;u||(u=c);var p={},f={spaces:{}};c.endsWith(" ")&&u.endsWith(" ")?(p.before=c.slice(0,c.length-1),f.spaces.before=u.slice(0,u.length-1)):c.startsWith(" ")&&u.startsWith(" ")?(p.after=c.slice(1),f.spaces.after=u.slice(1)):f.value=u,r=new m.default({value:" ",source:_(n,this.tokens[this.position-1]),sourceIndex:n[b.FIELDS.START_POS],spaces:p,raws:f})}return this.currToken&&this.currToken[b.FIELDS.TYPE]===v.space&&(r.spaces.after=this.optionalSpace(this.content()),this.position++),this.newNode(r)}var d=this.parseWhitespaceEquivalentTokens(t);if(d.length>0){var h=this.current.last;if(h){var y=this.convertWhitespaceNodesToSpace(d),g=y.space,E=y.rawSpace;void 0!==E&&(h.rawSpaceAfter+=E),h.spaces.after+=g}else d.forEach((function(t){return e.newNode(t)}))}},n.comma=function(){if(this.position===this.tokens.length-1)return this.root.trailingComma=!0,void this.position++;this.current._inferEndPosition();var e=new o.default({source:{start:C(this.tokens[this.position+1])}});this.current.parent.append(e),this.current=e,this.position++},n.comment=function(){var e=this.currToken;this.newNode(new l.default({value:this.content(),source:N(e),sourceIndex:e[b.FIELDS.START_POS]})),this.position++},n.error=function(e,t){throw this.root.error(e,t)},n.missingBackslash=function(){return this.error("Expected a backslash preceding the semicolon.",{index:this.currToken[b.FIELDS.START_POS]})},n.missingParenthesis=function(){return this.expected("opening parenthesis",this.currToken[b.FIELDS.START_POS])},n.missingSquareBracket=function(){return this.expected("opening square bracket",this.currToken[b.FIELDS.START_POS])},n.unexpected=function(){return this.error("Unexpected '"+this.content()+"'. Escaping special characters with \\ may help.",this.currToken[b.FIELDS.START_POS])},n.namespace=function(){var e=this.prevToken&&this.content(this.prevToken)||!0;return this.nextToken[b.FIELDS.TYPE]===v.word?(this.position++,this.word(e)):this.nextToken[b.FIELDS.TYPE]===v.asterisk?(this.position++,this.universal(e)):void 0},n.nesting=function(){if(this.nextToken&&"|"===this.content(this.nextToken))this.position++;else{var e=this.currToken;this.newNode(new y.default({value:this.content(),source:N(e),sourceIndex:e[b.FIELDS.START_POS]})),this.position++}},n.parentheses=function(){var e=this.current.last,t=1;if(this.position++,e&&e.type===E.PSEUDO){var r=new o.default({source:{start:C(this.tokens[this.position-1])}}),n=this.current;for(e.append(r),this.current=r;this.position1&&e.nextToken&&e.nextToken[b.FIELDS.TYPE]===v.openParenthesis&&e.error("Misplaced parenthesis.",{index:e.nextToken[b.FIELDS.START_POS]})})):this.expected(["pseudo-class","pseudo-element"],this.position-1)},n.space=function(){var e=this.content();0===this.position||this.prevToken[b.FIELDS.TYPE]===v.comma||this.prevToken[b.FIELDS.TYPE]===v.openParenthesis||this.current.nodes.every((function(e){return"comment"===e.type}))?(this.spaces=this.optionalSpace(e),this.position++):this.position===this.tokens.length-1||this.nextToken[b.FIELDS.TYPE]===v.comma||this.nextToken[b.FIELDS.TYPE]===v.closeParenthesis?(this.current.last.spaces.after=this.optionalSpace(e),this.position++):this.combinator()},n.string=function(){var e=this.currToken;this.newNode(new p.default({value:this.content(),source:N(e),sourceIndex:e[b.FIELDS.START_POS]})),this.position++},n.universal=function(e){var t=this.nextToken;if(t&&"|"===this.content(t))return this.position++,this.namespace();var r=this.currToken;this.newNode(new h.default({value:this.content(),source:N(r),sourceIndex:r[b.FIELDS.START_POS]}),e),this.position++},n.splitWord=function(e,t){for(var r=this,n=this.nextToken,s=this.content();n&&~[v.dollar,v.caret,v.equals,v.word].indexOf(n[b.FIELDS.TYPE]);){this.position++;var i=this.content();if(s+=i,i.lastIndexOf("\\")===i.length-1){var o=this.nextToken;o&&o[b.FIELDS.TYPE]===v.space&&(s+=this.requiredSpace(this.content(o)),this.position++)}n=this.nextToken}var l=D(s,".").filter((function(e){return"\\"!==s[e-1]})),p=D(s,"#").filter((function(e){return"\\"!==s[e-1]})),f=D(s,"#{");f.length&&(p=p.filter((function(e){return!~f.indexOf(e)})));var d=(0,g.default)(function(){var e=Array.prototype.concat.apply([],arguments);return e.filter((function(t,r){return r===e.indexOf(t)}))}([0].concat(l,p)));d.forEach((function(n,i){var o,f=d[i+1]||s.length,h=s.slice(n,f);if(0===i&&t)return t.call(r,h,d.length);var m=r.currToken,y=m[b.FIELDS.START_POS]+d[i],g=k(m[1],m[2]+n,m[3],m[2]+(f-1));if(~l.indexOf(n)){var v={value:h.slice(1),source:g,sourceIndex:y};o=new a.default(j(v,"value"))}else if(~p.indexOf(n)){var E={value:h.slice(1),source:g,sourceIndex:y};o=new c.default(j(E,"value"))}else{var x={value:h,source:g,sourceIndex:y};j(x,"value"),o=new u.default(x)}r.newNode(o,e),e=null})),this.position++},n.word=function(e){var t=this.nextToken;return t&&"|"===this.content(t)?(this.position++,this.namespace()):this.splitWord(e)},n.loop=function(){for(;this.position{"use strict";t.__esModule=!0,t.default=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0;){var s=r.shift();if(!e[s])return;e=e[s]}return e},e.exports=t.default},(e,t)=>{"use strict";t.__esModule=!0,t.default=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0;){var s=r.shift();e[s]||(e[s]={}),e=e[s]}},e.exports=t.default},(e,t)=>{"use strict";t.__esModule=!0,t.default=function(e){for(var t="",r=e.indexOf("/*"),n=0;r>=0;){t+=e.slice(n,r);var s=e.indexOf("*/",r+2);if(s<0)return t;n=s+2,r=e.indexOf("/*",n)}return t+e.slice(n)},e.exports=t.default},(e,t)=>{"use strict";t.__esModule=!0,t.default=function(e){return e.sort((function(e,t){return e-t}))},e.exports=t.default},function(e,t){!function(e){"use strict";for(var t={},r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n=0;n>>=5)>0&&(n|=32),t+=r[n]}while(e>0);return t}e.decode=function(e){for(var r=[],n=[],i=[0,0,0,0,0],o=0,a=0,l=0,c=0;a>>=1,d&&(c=0===c?-2147483648:-c),i[o]+=c,o++,c=l=0}}}return s(n,i,o),r.push(n),r},e.encode=function(e){for(var t=0,r=0,n=0,s=0,o="",a=0;a0&&(o+=";"),0!==l.length){for(var c=0,u=[],p=0,f=l;p1&&(h+=i(d[1]-t)+i(d[2]-r)+i(d[3]-n),t=d[1],r=d[2],n=d[3]),5===d.length&&(h+=i(d[4]-s),s=d[4]),u.push(h)}o+=u.join(",")}}return o},Object.defineProperty(e,"__esModule",{value:!0})}(t)},(e,t,r)=>{"use strict";var n,s=r(180),i=r(31),o=r(2),a=r(24),l=r(17),c=r(181),u=r(32),p=r(119),f=r(112).f,d=r(188),h=r(190),m=r(54),y=r(58),g=o.Int8Array,b=g&&g.prototype,v=o.Uint8ClampedArray,E=v&&v.prototype,x=g&&d(g),S=b&&d(b),T=Object.prototype,w=T.isPrototypeOf,P=m("toStringTag"),A=y("TYPED_ARRAY_TAG"),O=s&&!!h&&"Opera"!==c(o.opera),C=!1,I={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},k={BigInt64Array:8,BigUint64Array:8},N=function(e){if(!a(e))return!1;var t=c(e);return l(I,t)||l(k,t)};for(n in I)o[n]||(O=!1);if((!O||"function"!=typeof x||x===Function.prototype)&&(x=function(){throw TypeError("Incorrect invocation")},O))for(n in I)o[n]&&h(o[n],x);if((!O||!S||S===T)&&(S=x.prototype,O))for(n in I)o[n]&&h(o[n].prototype,S);if(O&&d(E)!==S&&h(E,S),i&&!l(S,P))for(n in C=!0,f(S,P,{get:function(){return a(this)?this[A]:void 0}}),I)o[n]&&u(o[n],A,n);e.exports={NATIVE_ARRAY_BUFFER_VIEWS:O,TYPED_ARRAY_TAG:C&&A,aTypedArray:function(e){if(N(e))return e;throw TypeError("Target is not a typed array")},aTypedArrayConstructor:function(e){if(h){if(w.call(x,e))return e}else for(var t in I)if(l(I,n)){var r=o[t];if(r&&(e===r||w.call(r,e)))return e}throw TypeError("Target is not a typed array constructor")},exportTypedArrayMethod:function(e,t,r){if(i){if(r)for(var n in I){var s=o[n];if(s&&l(s.prototype,e))try{delete s.prototype[e]}catch(e){}}S[e]&&!r||p(S,e,r?t:O&&b[e]||t)}},exportTypedArrayStaticMethod:function(e,t,r){var n,s;if(i){if(h){if(r)for(n in I)if((s=o[n])&&l(s,e))try{delete s[e]}catch(e){}if(x[e]&&!r)return;try{return p(x,e,r?t:O&&x[e]||t)}catch(e){}}for(n in I)!(s=o[n])||s[e]&&!r||p(s,e,t)}},isView:function(e){if(!a(e))return!1;var t=c(e);return"DataView"===t||l(I,t)||l(k,t)},isTypedArray:N,TypedArray:x,TypedArrayPrototype:S}},e=>{e.exports="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof DataView},(e,t,r)=>{var n=r(182),s=r(60),i=r(54)("toStringTag"),o="Arguments"==s(function(){return arguments}());e.exports=n?s:function(e){var t,r,n;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),i))?r:o?s(t):"Object"==(n=s(t))&&"function"==typeof t.callee?"Arguments":n}},(e,t,r)=>{var n={};n[r(54)("toStringTag")]="z",e.exports="[object z]"===String(n)},e=>{e.exports=!1},(e,t,r)=>{var n=r(2);e.exports=n},(e,t,r)=>{var n=r(117);e.exports=n&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},(e,t,r)=>{var n,s,i,o=r(187),a=r(2),l=r(24),c=r(32),u=r(17),p=r(55),f=r(121),d=r(122),h="Object already initialized",m=a.WeakMap;if(o||p.state){var y=p.state||(p.state=new m),g=y.get,b=y.has,v=y.set;n=function(e,t){if(b.call(y,e))throw new TypeError(h);return t.facade=e,v.call(y,e,t),t},s=function(e){return g.call(y,e)||{}},i=function(e){return b.call(y,e)}}else{var E=f("state");d[E]=!0,n=function(e,t){if(u(e,E))throw new TypeError(h);return t.facade=e,c(e,E,t),t},s=function(e){return u(e,E)?e[E]:{}},i=function(e){return u(e,E)}}e.exports={set:n,get:s,has:i,enforce:function(e){return i(e)?s(e):n(e,{})},getterFor:function(e){return function(t){var r;if(!l(t)||(r=s(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return r}}}},(e,t,r)=>{var n=r(2),s=r(120),i=n.WeakMap;e.exports="function"==typeof i&&/native code/.test(s(i))},(e,t,r)=>{var n=r(17),s=r(109),i=r(121),o=r(189),a=i("IE_PROTO"),l=Object.prototype;e.exports=o?Object.getPrototypeOf:function(e){return e=s(e),n(e,a)?e[a]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?l:null}},(e,t,r)=>{var n=r(16);e.exports=!n((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype}))},(e,t,r)=>{var n=r(57),s=r(191);e.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var e,t=!1,r={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(r,[]),t=r instanceof Array}catch(e){}return function(r,i){return n(r),s(i),t?e.call(r,i):r.__proto__=i,r}}():void 0)},(e,t,r)=>{var n=r(24);e.exports=function(e){if(!n(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},e=>{var t=Math.floor,r=function(e,i){var o=e.length,a=t(o/2);return o<8?n(e,i):s(r(e.slice(0,a),i),r(e.slice(a),i),i)},n=function(e,t){for(var r,n,s=e.length,i=1;i0;)e[n]=e[--n];n!==i++&&(e[n]=r)}return e},s=function(e,t,r){for(var n=e.length,s=t.length,i=0,o=0,a=[];i{var n=r(33).match(/firefox\/(\d+)/i);e.exports=!!n&&+n[1]},(e,t,r)=>{var n=r(33);e.exports=/MSIE|Trident/.test(n)},(e,t,r)=>{var n=r(33).match(/AppleWebKit\/(\d+)\./);e.exports=!!n&&+n[1]},(e,t,r)=>{var n=r(2),s=r(197).f,i=r(32),o=r(119),a=r(56),l=r(199),c=r(205);e.exports=function(e,t){var r,u,p,f,d,h=e.target,m=e.global,y=e.stat;if(r=m?n:y?n[h]||a(h,{}):(n[h]||{}).prototype)for(u in t){if(f=t[u],p=e.noTargetGet?(d=s(r,u))&&d.value:r[u],!c(m?u:h+(y?".":"#")+u,e.forced)&&void 0!==p){if(typeof f==typeof p)continue;l(f,p)}(e.sham||p&&p.sham)&&i(f,"sham",!0),o(r,u,f,e)}}},(e,t,r)=>{var n=r(31),s=r(358),i=r(116),o=r(61),a=r(115),l=r(17),c=r(113),u=Object.getOwnPropertyDescriptor;t.f=n?u:function(e,t){if(e=o(e),t=a(t,!0),c)try{return u(e,t)}catch(e){}if(l(e,t))return i(!s.f.call(e,t),e[t])}},(e,t,r)=>{var n=r(16),s=r(60),i="".split;e.exports=n((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==s(e)?i.call(e,""):Object(e)}:Object},(e,t,r)=>{var n=r(17),s=r(200),i=r(197),o=r(112);e.exports=function(e,t){for(var r=s(t),a=o.f,l=i.f,c=0;c{var n=r(59),s=r(359),i=r(360),o=r(57);e.exports=n("Reflect","ownKeys")||function(e){var t=s.f(o(e)),r=i.f;return r?t.concat(r(e)):t}},(e,t,r)=>{var n=r(17),s=r(61),i=r(202).indexOf,o=r(122);e.exports=function(e,t){var r,a=s(e),l=0,c=[];for(r in a)!n(o,r)&&n(a,r)&&c.push(r);for(;t.length>l;)n(a,r=t[l++])&&(~i(c,r)||c.push(r));return c}},(e,t,r)=>{var n=r(61),s=r(124),i=r(203),o=function(e){return function(t,r,o){var a,l=n(t),c=s(l.length),u=i(o,c);if(e&&r!=r){for(;c>u;)if((a=l[u++])!=a)return!0}else for(;c>u;u++)if((e||u in l)&&l[u]===r)return e||u||0;return!e&&-1}};e.exports={includes:o(!0),indexOf:o(!1)}},(e,t,r)=>{var n=r(125),s=Math.max,i=Math.min;e.exports=function(e,t){var r=n(e);return r<0?s(r+t,0):i(r,t)}},e=>{e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},(e,t,r)=>{var n=r(16),s=/#|\.prototype\./,i=function(e,t){var r=a[o(e)];return r==c||r!=l&&("function"==typeof t?n(t):!!t)},o=i.normalize=function(e){return String(e).replace(s,".").toLowerCase()},a=i.data={},l=i.NATIVE="N",c=i.POLYFILL="P";e.exports=i},(e,t,r)=>{var n,s,i,o=r(2),a=r(16),l=r(207),c=r(208),u=r(114),p=r(209),f=r(210),d=o.location,h=o.setImmediate,m=o.clearImmediate,y=o.process,g=o.MessageChannel,b=o.Dispatch,v=0,E={},x=function(e){if(E.hasOwnProperty(e)){var t=E[e];delete E[e],t()}},S=function(e){return function(){x(e)}},T=function(e){x(e.data)},w=function(e){o.postMessage(e+"",d.protocol+"//"+d.host)};h&&m||(h=function(e){for(var t=[],r=1;arguments.length>r;)t.push(arguments[r++]);return E[++v]=function(){("function"==typeof e?e:Function(e)).apply(void 0,t)},n(v),v},m=function(e){delete E[e]},f?n=function(e){y.nextTick(S(e))}:b&&b.now?n=function(e){b.now(S(e))}:g&&!p?(i=(s=new g).port2,s.port1.onmessage=T,n=l(i.postMessage,i,1)):o.addEventListener&&"function"==typeof postMessage&&!o.importScripts&&d&&"file:"!==d.protocol&&!a(w)?(n=w,o.addEventListener("message",T,!1)):n="onreadystatechange"in u("script")?function(e){c.appendChild(u("script")).onreadystatechange=function(){c.removeChild(this),x(e)}}:function(e){setTimeout(S(e),0)}),e.exports={set:h,clear:m}},(e,t,r)=>{var n=r(123);e.exports=function(e,t,r){if(n(e),void 0===t)return e;switch(r){case 0:return function(){return e.call(t)};case 1:return function(r){return e.call(t,r)};case 2:return function(r,n){return e.call(t,r,n)};case 3:return function(r,n,s){return e.call(t,r,n,s)}}return function(){return e.apply(t,arguments)}}},(e,t,r)=>{var n=r(59);e.exports=n("document","documentElement")},(e,t,r)=>{var n=r(33);e.exports=/(?:iphone|ipod|ipad).*applewebkit/i.test(n)},(e,t,r)=>{var n=r(60),s=r(2);e.exports="process"==n(s.process)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.get=u,t.minVersion=function(e){return c(e).minVersion()},t.getDependencies=function(e){return Array.from(c(e).dependencies.values())},t.ensure=function(e,t){a||(a=t),c(e)},t.default=t.list=void 0;var n=r(10),s=r(0),i=r(457);function o(e){const t=[];for(;e.parentPath;e=e.parentPath)t.push(e.key),e.inList&&t.push(e.listKey);return t.reverse().join(".")}let a;const l=Object.create(null);function c(e){if(!l[e]){const t=i.default[e];if(!t)throw Object.assign(new ReferenceError(`Unknown helper ${e}`),{code:"BABEL_HELPER_UNKNOWN",helper:e});const r=()=>{const r={ast:s.file(t.ast())};return a?new a({filename:`babel-helper://${e}`},r):r},c=function(e){const t=new Set,r=new Set,s=new Map;let a,l;const c=[],u=[],p=[],f={ImportDeclaration(e){const t=e.node.source.value;if(!i.default[t])throw e.buildCodeFrameError(`Unknown helper ${t}`);if(1!==e.get("specifiers").length||!e.get("specifiers.0").isImportDefaultSpecifier())throw e.buildCodeFrameError("Helpers can only import a default value");const r=e.node.specifiers[0].local;s.set(r,t),u.push(o(e))},ExportDefaultDeclaration(e){const t=e.get("declaration");if(t.isFunctionDeclaration()){if(!t.node.id)throw t.buildCodeFrameError("Helpers should give names to their exported func declaration");a=t.node.id.name}l=o(e)},ExportAllDeclaration(e){throw e.buildCodeFrameError("Helpers can only export default")},ExportNamedDeclaration(e){throw e.buildCodeFrameError("Helpers can only export default")},Statement(e){e.isModuleDeclaration()||e.skip()}},d={Program(e){const t=e.scope.getAllBindings();Object.keys(t).forEach((e=>{e!==a&&(s.has(t[e].identifier)||r.add(e))}))},ReferencedIdentifier(e){const r=e.node.name,n=e.scope.getBinding(r,!0);n?s.has(n.identifier)&&p.push(o(e)):t.add(r)},AssignmentExpression(e){const t=e.get("left");if(!(a in t.getBindingIdentifiers()))return;if(!t.isIdentifier())throw t.buildCodeFrameError("Only simple assignments to exports are allowed in helpers");const r=e.scope.getBinding(a);null!=r&&r.scope.path.isProgram()&&c.push(o(e))}};if((0,n.default)(e.ast,f,e.scope),(0,n.default)(e.ast,d,e.scope),!l)throw new Error("Helpers must default-export something.");return c.reverse(),{globals:Array.from(t),localBindingNames:Array.from(r),dependencies:s,exportBindingAssignments:c,exportPath:l,exportName:a,importBindingsReferences:p,importPaths:u}}(r());l[e]={build(e,t,i){const o=r();return function(e,t,r,i,o){if(i&&!r)throw new Error("Unexpected local bindings for module-based helpers.");if(!r)return;const{localBindingNames:a,dependencies:l,exportBindingAssignments:c,exportPath:u,exportName:p,importBindingsReferences:f,importPaths:d}=t,h={};l.forEach(((e,t)=>{h[t.name]="function"==typeof o&&o(e)||t}));const m={},y=new Set(i||[]);a.forEach((e=>{let t=e;for(;y.has(t);)t="_"+t;t!==e&&(m[e]=t)})),"Identifier"===r.type&&p!==r.name&&(m[p]=r.name);const g={Program(e){const t=e.get(u),n=d.map((t=>e.get(t))),i=f.map((t=>e.get(t))),o=t.get("declaration");if("Identifier"===r.type)o.isFunctionDeclaration()?t.replaceWith(o):t.replaceWith(s.variableDeclaration("var",[s.variableDeclarator(r,o.node)]));else{if("MemberExpression"!==r.type)throw new Error("Unexpected helper format.");o.isFunctionDeclaration()?(c.forEach((t=>{const n=e.get(t);n.replaceWith(s.assignmentExpression("=",r,n.node))})),t.replaceWith(o),e.pushContainer("body",s.expressionStatement(s.assignmentExpression("=",r,s.identifier(p))))):t.replaceWith(s.expressionStatement(s.assignmentExpression("=",r,o.node)))}Object.keys(m).forEach((t=>{e.scope.rename(t,m[t])}));for(const e of n)e.remove();for(const e of i){const t=s.cloneNode(h[e.node.name]);e.replaceWith(t)}e.stop()}};(0,n.default)(e.ast,g,e.scope)}(o,c,t,i,e),{nodes:o.ast.program.body,globals:c.globals}},minVersion:()=>t.minVersion,dependencies:c.dependencies}}return l[e]}function u(e,t,r,n){return c(e).build(t,r,n)}const p=Object.keys(i.default).map((e=>e.replace(/^_/,""))).filter((e=>"__esModule"!==e));t.list=p;var f=u;t.default=f},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ForAwaitStatement=t.NumericLiteralTypeAnnotation=t.ExistentialTypeParam=t.SpreadProperty=t.RestProperty=t.Flow=t.Pure=t.Generated=t.User=t.Var=t.BlockScoped=t.Referenced=t.Scope=t.Expression=t.Statement=t.BindingIdentifier=t.ReferencedMemberExpression=t.ReferencedIdentifier=void 0;var n=r(0);const s={types:["Identifier","JSXIdentifier"],checkPath(e,t){const{node:r,parent:s}=e;if(!n.isIdentifier(r,t)&&!n.isJSXMemberExpression(s,t)){if(!n.isJSXIdentifier(r,t))return!1;if(n.react.isCompatTag(r.name))return!1}return n.isReferenced(r,s,e.parentPath.parent)}};t.ReferencedIdentifier=s;const i={types:["MemberExpression"],checkPath:({node:e,parent:t})=>n.isMemberExpression(e)&&n.isReferenced(e,t)};t.ReferencedMemberExpression=i;const o={types:["Identifier"],checkPath(e){const{node:t,parent:r}=e,s=e.parentPath.parent;return n.isIdentifier(t)&&n.isBinding(t,r,s)}};t.BindingIdentifier=o;const a={types:["Statement"],checkPath({node:e,parent:t}){if(n.isStatement(e)){if(n.isVariableDeclaration(e)){if(n.isForXStatement(t,{left:e}))return!1;if(n.isForStatement(t,{init:e}))return!1}return!0}return!1}};t.Statement=a;const l={types:["Expression"],checkPath:e=>e.isIdentifier()?e.isReferencedIdentifier():n.isExpression(e.node)};t.Expression=l;const c={types:["Scopable","Pattern"],checkPath:e=>n.isScope(e.node,e.parent)};t.Scope=c;const u={checkPath:e=>n.isReferenced(e.node,e.parent)};t.Referenced=u;const p={checkPath:e=>n.isBlockScoped(e.node)};t.BlockScoped=p;const f={types:["VariableDeclaration"],checkPath:e=>n.isVar(e.node)};t.Var=f;t.User={checkPath:e=>e.node&&!!e.node.loc};t.Generated={checkPath:e=>!e.isUser()};t.Pure={checkPath:(e,t)=>e.scope.isPure(e.node,t)};const d={types:["Flow","ImportDeclaration","ExportDeclaration","ImportSpecifier"],checkPath:({node:e})=>!(!n.isFlow(e)&&(n.isImportDeclaration(e)?"type"!==e.importKind&&"typeof"!==e.importKind:n.isExportDeclaration(e)?"type"!==e.exportKind:!n.isImportSpecifier(e)||"type"!==e.importKind&&"typeof"!==e.importKind))};t.Flow=d;t.RestProperty={types:["RestElement"],checkPath:e=>e.parentPath&&e.parentPath.isObjectPattern()};t.SpreadProperty={types:["RestElement"],checkPath:e=>e.parentPath&&e.parentPath.isObjectExpression()},t.ExistentialTypeParam={types:["ExistsTypeAnnotation"]},t.NumericLiteralTypeAnnotation={types:["NumberLiteralTypeAnnotation"]};t.ForAwaitStatement={types:["ForOfStatement"],checkPath:({node:e})=>!0===e.await}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const r=e.split(".");return e=>(0,n.default)(e,r,t)};var n=r(214)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){if(!(0,n.isMemberExpression)(e))return!1;const s=Array.isArray(t)?t:t.split("."),i=[];let o;for(o=e;(0,n.isMemberExpression)(o);o=o.object)i.push(o.property);if(i.push(o),i.lengths.length)return!1;for(let e=0,t=i.length-1;e{"use strict";let t=null;function r(e){if(null!==t&&(t.property,1)){const e=t;return t=r.prototype=null,e}return t=r.prototype=null==e?Object.create(null):e,new r}r(),e.exports=function(e){return r(e)}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){if(e===t)return!0;const r=n.PLACEHOLDERS_ALIAS[e];if(r)for(const e of r)if(t===e)return!0;return!1};var n=r(11)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PLACEHOLDERS_FLIPPED_ALIAS=t.PLACEHOLDERS_ALIAS=t.PLACEHOLDERS=void 0;var n=r(20);const s=["Identifier","StringLiteral","Expression","Statement","Declaration","BlockStatement","ClassBody","Pattern"];t.PLACEHOLDERS=s;const i={Declaration:["Statement"],Pattern:["PatternLike","LVal"]};t.PLACEHOLDERS_ALIAS=i;for(const e of s){const t=n.ALIAS_KEYS[e];null!=t&&t.length&&(i[e]=t)}const o={};t.PLACEHOLDERS_FLIPPED_ALIAS=o,Object.keys(i).forEach((e=>{i[e].forEach((t=>{Object.hasOwnProperty.call(o,t)||(o[t]=[]),o[t].push(e)}))}))},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return!(!e||!n.VISITOR_KEYS[e.type])};var n=r(11)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t){const r={},i={},o=[],a=[];for(let l=0;l=0)){if((0,n.isAnyTypeAnnotation)(c))return[c];if((0,n.isFlowBaseAnnotation)(c))i[c.type]=c;else if((0,n.isUnionTypeAnnotation)(c))o.indexOf(c.types)<0&&(t=t.concat(c.types),o.push(c.types));else if((0,n.isGenericTypeAnnotation)(c)){const t=s(c.id);if(r[t]){let n=r[t];n.typeParameters?c.typeParameters&&(n.typeParameters.params=e(n.typeParameters.params.concat(c.typeParameters.params))):n=c.typeParameters}else r[t]=c}else a.push(c)}}for(const e of Object.keys(i))a.push(i[e]);for(const e of Object.keys(r))a.push(r[e]);return a};var n=r(1);function s(e){return(0,n.isIdentifier)(e)?e.name:`${e.id.name}.${s(e.qualification)}`}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){if(!r||!e)return e;const n=`${t}Comments`;return e[n]?e[n]="leading"===t?r.concat(e[n]):e[n].concat(r):e[n]=r,e}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){(0,n.default)("innerComments",e,t)};var n=r(131)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){(0,n.default)("leadingComments",e,t)};var n=r(131)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){return(0,n.default)(e,t),(0,s.default)(e,t),(0,i.default)(e,t),e};var n=r(224),s=r(222),i=r(221)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){(0,n.default)("trailingComments",e,t)};var n=r(131)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){if((0,n.isBlockStatement)(e))return e;let r=[];return(0,n.isEmptyStatement)(e)?r=[]:((0,n.isStatement)(e)||(e=(0,n.isFunction)(t)?(0,s.returnStatement)(e):(0,s.expressionStatement)(e)),r=[e]),(0,s.blockStatement)(r)};var n=r(1),s=r(6)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){e+="";let t="";for(const r of e)t+=(0,s.isIdentifierChar)(r.codePointAt(0))?r:"-";return t=t.replace(/^[-0-9]+/,""),t=t.replace(/[-\s]+(.)?/g,(function(e,t){return t?t.toUpperCase():""})),(0,n.default)(t)||(t=`_${t}`),t||"_"};var n=r(38),s=r(63)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){return(0,n.default)(e,s.default,t),e};var n=r(228),s=r(229)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t,r,s){if(!t)return;const i=n.VISITOR_KEYS[t.type];if(i){r(t,s=s||{});for(const n of i){const i=t[n];if(Array.isArray(i))for(const t of i)e(t,r,s);else e(i,r,s)}}};var n=r(11)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t={}){const r=t.preserveComments?s:i;for(const t of r)null!=e[t]&&(e[t]=void 0);for(const t of Object.keys(e))"_"===t[0]&&null!=e[t]&&(e[t]=void 0);const n=Object.getOwnPropertySymbols(e);for(const t of n)e[t]=null};var n=r(25);const s=["tokens","start","end","loc","raw","rawValue"],i=n.COMMENT_KEYS.concat(["comments"]).concat(s)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return(0,n.isVariableDeclaration)(e)&&("var"!==e.kind||e[s.BLOCK_SCOPED_SYMBOL])};var n=r(1),s=r(25)},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=r(413),s=r(10),i=r(232),o=r(414),a=r(0),l=r(34);function c(e,t){switch(null==e?void 0:e.type){default:if(a.isModuleDeclaration(e))if((a.isExportAllDeclaration(e)||a.isExportNamedDeclaration(e)||a.isImportDeclaration(e))&&e.source)c(e.source,t);else if((a.isExportNamedDeclaration(e)||a.isImportDeclaration(e))&&e.specifiers&&e.specifiers.length)for(const r of e.specifiers)c(r,t);else(a.isExportDefaultDeclaration(e)||a.isExportNamedDeclaration(e))&&e.declaration&&c(e.declaration,t);else a.isModuleSpecifier(e)?c(e.local,t):a.isLiteral(e)&&t.push(e.value);break;case"MemberExpression":case"OptionalMemberExpression":case"JSXMemberExpression":c(e.object,t),c(e.property,t);break;case"Identifier":case"JSXIdentifier":t.push(e.name);break;case"CallExpression":case"OptionalCallExpression":case"NewExpression":c(e.callee,t);break;case"ObjectExpression":case"ObjectPattern":for(const r of e.properties)c(r,t);break;case"SpreadElement":case"RestElement":c(e.argument,t);break;case"ObjectProperty":case"ObjectMethod":case"ClassProperty":case"ClassMethod":case"ClassPrivateProperty":case"ClassPrivateMethod":c(e.key,t);break;case"ThisExpression":t.push("this");break;case"Super":t.push("super");break;case"Import":t.push("import");break;case"DoExpression":t.push("do");break;case"YieldExpression":t.push("yield"),c(e.argument,t);break;case"AwaitExpression":t.push("await"),c(e.argument,t);break;case"AssignmentExpression":c(e.left,t);break;case"VariableDeclarator":c(e.id,t);break;case"FunctionExpression":case"FunctionDeclaration":case"ClassExpression":case"ClassDeclaration":case"PrivateName":c(e.id,t);break;case"ParenthesizedExpression":c(e.expression,t);break;case"UnaryExpression":case"UpdateExpression":c(e.argument,t);break;case"MetaProperty":c(e.meta,t),c(e.property,t);break;case"JSXElement":c(e.openingElement,t);break;case"JSXOpeningElement":t.push(e.name);break;case"JSXFragment":c(e.openingFragment,t);break;case"JSXOpeningFragment":t.push("Fragment");break;case"JSXNamespacedName":c(e.namespace,t),c(e.name,t)}}const u={For(e){for(const t of a.FOR_INIT_KEYS){const r=e.get(t);r.isVar()&&(e.scope.getFunctionParent()||e.scope.getProgramParent()).registerBinding("var",r)}},Declaration(e){e.isBlockScoped()||e.isExportDeclaration()||(e.scope.getFunctionParent()||e.scope.getProgramParent()).registerDeclaration(e)},ReferencedIdentifier(e,t){t.references.push(e)},ForXStatement(e,t){const r=e.get("left");(r.isPattern()||r.isIdentifier())&&t.constantViolations.push(e)},ExportDeclaration:{exit(e){const{node:t,scope:r}=e;if(a.isExportAllDeclaration(t))return;const n=t.declaration;if(a.isClassDeclaration(n)||a.isFunctionDeclaration(n)){const t=n.id;if(!t)return;const s=r.getBinding(t.name);s&&s.reference(e)}else if(a.isVariableDeclaration(n))for(const t of n.declarations)for(const n of Object.keys(a.getBindingIdentifiers(t))){const t=r.getBinding(n);t&&t.reference(e)}}},LabeledStatement(e){e.scope.getBlockParent().registerDeclaration(e)},AssignmentExpression(e,t){t.assignments.push(e)},UpdateExpression(e,t){t.constantViolations.push(e)},UnaryExpression(e,t){"delete"===e.node.operator&&t.constantViolations.push(e)},BlockScoped(e){let t=e.scope;if(t.path===e&&(t=t.parent),t.getBlockParent().registerDeclaration(e),e.isClassDeclaration()&&e.node.id){const t=e.node.id.name;e.scope.bindings[t]=e.scope.parent.getBinding(t)}},CatchClause(e){e.scope.registerBinding("let",e)},Function(e){e.isFunctionExpression()&&e.has("id")&&!e.get("id").node[a.NOT_LOCAL_BINDING]&&e.scope.registerBinding("local",e.get("id"),e);const t=e.get("params");for(const r of t)e.scope.registerBinding("param",r)},ClassExpression(e){e.has("id")&&!e.get("id").node[a.NOT_LOCAL_BINDING]&&e.scope.registerBinding("local",e)}};let p=0;class f{constructor(e){this.uid=void 0,this.path=void 0,this.block=void 0,this.labels=void 0,this.inited=void 0,this.bindings=void 0,this.references=void 0,this.globals=void 0,this.uids=void 0,this.data=void 0,this.crawling=void 0;const{node:t}=e,r=l.scope.get(t);if((null==r?void 0:r.path)===e)return r;l.scope.set(t,this),this.uid=p++,this.block=t,this.path=e,this.labels=new Map,this.inited=!1}get parent(){var e;let t,r=this.path;do{const e="key"===r.key;r=r.parentPath,e&&r.isMethod()&&(r=r.parentPath),r&&r.isScope()&&(t=r)}while(r&&!t);return null==(e=t)?void 0:e.scope}get parentBlock(){return this.path.parent}get hub(){return this.path.hub}traverse(e,t,r){(0,s.default)(e,t,this,r,this.path)}generateDeclaredUidIdentifier(e){const t=this.generateUidIdentifier(e);return this.push({id:t}),a.cloneNode(t)}generateUidIdentifier(e){return a.identifier(this.generateUid(e))}generateUid(e="temp"){let t;e=a.toIdentifier(e).replace(/^_+/,"").replace(/[0-9]+$/g,"");let r=1;do{t=this._generateUid(e,r),r++}while(this.hasLabel(t)||this.hasBinding(t)||this.hasGlobal(t)||this.hasReference(t));const n=this.getProgramParent();return n.references[t]=!0,n.uids[t]=!0,t}_generateUid(e,t){let r=e;return t>1&&(r+=t),`_${r}`}generateUidBasedOnNode(e,t){const r=[];c(e,r);let n=r.join("$");return n=n.replace(/^_/,"")||t||"ref",this.generateUid(n.slice(0,20))}generateUidIdentifierBasedOnNode(e,t){return a.identifier(this.generateUidBasedOnNode(e,t))}isStatic(e){if(a.isThisExpression(e)||a.isSuper(e))return!0;if(a.isIdentifier(e)){const t=this.getBinding(e.name);return t?t.constant:this.hasBinding(e.name)}return!1}maybeGenerateMemoised(e,t){if(this.isStatic(e))return null;{const r=this.generateUidIdentifierBasedOnNode(e);return t?r:(this.push({id:r}),a.cloneNode(r))}}checkBlockScopedCollisions(e,t,r,n){if("param"!==t&&"local"!==e.kind&&("let"===t||"let"===e.kind||"const"===e.kind||"module"===e.kind||"param"===e.kind&&("let"===t||"const"===t)))throw this.hub.buildError(n,`Duplicate declaration "${r}"`,TypeError)}rename(e,t,r){const s=this.getBinding(e);if(s)return t=t||this.generateUidIdentifier(e).name,new n.default(s,e,t).rename(r)}_renameFromMap(e,t,r,n){e[t]&&(e[r]=n,e[t]=null)}dump(){"-".repeat(60);let e=this;do{for(const t of Object.keys(e.bindings))e.bindings[t]}while(e=e.parent)}toArray(e,t,r){if(a.isIdentifier(e)){const t=this.getBinding(e.name);if(null!=t&&t.constant&&t.path.isGenericType("Array"))return e}if(a.isArrayExpression(e))return e;if(a.isIdentifier(e,{name:"arguments"}))return a.callExpression(a.memberExpression(a.memberExpression(a.memberExpression(a.identifier("Array"),a.identifier("prototype")),a.identifier("slice")),a.identifier("call")),[e]);let n;const s=[e];return!0===t?n="toConsumableArray":t?(s.push(a.numericLiteral(t)),n="slicedToArray"):n="toArray",r&&(s.unshift(this.hub.addHelper(n)),n="maybeArrayLike"),a.callExpression(this.hub.addHelper(n),s)}hasLabel(e){return!!this.getLabel(e)}getLabel(e){return this.labels.get(e)}registerLabel(e){this.labels.set(e.node.label.name,e)}registerDeclaration(e){if(e.isLabeledStatement())this.registerLabel(e);else if(e.isFunctionDeclaration())this.registerBinding("hoisted",e.get("id"),e);else if(e.isVariableDeclaration()){const t=e.get("declarations");for(const r of t)this.registerBinding(e.node.kind,r)}else if(e.isClassDeclaration())this.registerBinding("let",e);else if(e.isImportDeclaration()){const t=e.get("specifiers");for(const e of t)this.registerBinding("module",e)}else if(e.isExportDeclaration()){const t=e.get("declaration");(t.isClassDeclaration()||t.isFunctionDeclaration()||t.isVariableDeclaration())&&this.registerDeclaration(t)}else this.registerBinding("unknown",e)}buildUndefinedNode(){return a.unaryExpression("void",a.numericLiteral(0),!0)}registerConstantViolation(e){const t=e.getBindingIdentifiers();for(const r of Object.keys(t)){const t=this.getBinding(r);t&&t.reassign(e)}}registerBinding(e,t,r=t){if(!e)throw new ReferenceError("no `kind`");if(t.isVariableDeclaration()){const r=t.get("declarations");for(const t of r)this.registerBinding(e,t);return}const n=this.getProgramParent(),s=t.getOuterBindingIdentifiers(!0);for(const t of Object.keys(s)){n.references[t]=!0;for(const n of s[t]){const s=this.getOwnBinding(t);if(s){if(s.identifier===n)continue;this.checkBlockScopedCollisions(s,e,t,n)}s?this.registerConstantViolation(r):this.bindings[t]=new i.default({identifier:n,scope:this,path:r,kind:e})}}}addGlobal(e){this.globals[e.name]=e}hasUid(e){let t=this;do{if(t.uids[e])return!0}while(t=t.parent);return!1}hasGlobal(e){let t=this;do{if(t.globals[e])return!0}while(t=t.parent);return!1}hasReference(e){return!!this.getProgramParent().references[e]}isPure(e,t){if(a.isIdentifier(e)){const r=this.getBinding(e.name);return!!r&&(!t||r.constant)}if(a.isClass(e))return!(e.superClass&&!this.isPure(e.superClass,t))&&this.isPure(e.body,t);if(a.isClassBody(e)){for(const r of e.body)if(!this.isPure(r,t))return!1;return!0}if(a.isBinary(e))return this.isPure(e.left,t)&&this.isPure(e.right,t);if(a.isArrayExpression(e)){for(const r of e.elements)if(!this.isPure(r,t))return!1;return!0}if(a.isObjectExpression(e)){for(const r of e.properties)if(!this.isPure(r,t))return!1;return!0}if(a.isMethod(e))return!(e.computed&&!this.isPure(e.key,t))&&"get"!==e.kind&&"set"!==e.kind;if(a.isProperty(e))return!(e.computed&&!this.isPure(e.key,t))&&this.isPure(e.value,t);if(a.isUnaryExpression(e))return this.isPure(e.argument,t);if(a.isTaggedTemplateExpression(e))return a.matchesPattern(e.tag,"String.raw")&&!this.hasBinding("String",!0)&&this.isPure(e.quasi,t);if(a.isTemplateLiteral(e)){for(const r of e.expressions)if(!this.isPure(r,t))return!1;return!0}return a.isPureish(e)}setData(e,t){return this.data[e]=t}getData(e){let t=this;do{const r=t.data[e];if(null!=r)return r}while(t=t.parent)}removeData(e){let t=this;do{null!=t.data[e]&&(t.data[e]=null)}while(t=t.parent)}init(){this.inited||(this.inited=!0,this.crawl())}crawl(){const e=this.path;this.references=Object.create(null),this.bindings=Object.create(null),this.globals=Object.create(null),this.uids=Object.create(null),this.data=Object.create(null);const t=this.getProgramParent();if(t.crawling)return;const r={references:[],constantViolations:[],assignments:[]};if(this.crawling=!0,"Program"!==e.type&&u._exploded){for(const t of u.enter)t(e,r);const t=u[e.type];if(t)for(const n of t.enter)n(e,r)}e.traverse(u,r),this.crawling=!1;for(const e of r.assignments){const r=e.getBindingIdentifiers();for(const n of Object.keys(r))e.scope.getBinding(n)||t.addGlobal(r[n]);e.scope.registerConstantViolation(e)}for(const e of r.references){const r=e.scope.getBinding(e.node.name);r?r.reference(e):t.addGlobal(e.node)}for(const e of r.constantViolations)e.scope.registerConstantViolation(e)}push(e){let t=this.path;t.isBlockStatement()||t.isProgram()||(t=this.getBlockParent().path),t.isSwitchStatement()&&(t=(this.getFunctionParent()||this.getProgramParent()).path),(t.isLoop()||t.isCatchClause()||t.isFunction())&&(t.ensureBlock(),t=t.get("body"));const r=e.unique,n=e.kind||"var",s=null==e._blockHoist?2:e._blockHoist,i=`declaration:${n}:${s}`;let o=!r&&t.getData(i);if(!o){const e=a.variableDeclaration(n,[]);e._blockHoist=s,[o]=t.unshiftContainer("body",[e]),r||t.setData(i,o)}const l=a.variableDeclarator(e.id,e.init);o.node.declarations.push(l),this.registerBinding(n,o.get("declarations").pop())}getProgramParent(){let e=this;do{if(e.path.isProgram())return e}while(e=e.parent);throw new Error("Couldn't find a Program")}getFunctionParent(){let e=this;do{if(e.path.isFunctionParent())return e}while(e=e.parent);return null}getBlockParent(){let e=this;do{if(e.path.isBlockParent())return e}while(e=e.parent);throw new Error("We couldn't find a BlockStatement, For, Switch, Function, Loop or Program...")}getAllBindings(){const e=Object.create(null);let t=this;do{for(const r of Object.keys(t.bindings))r in e==0&&(e[r]=t.bindings[r]);t=t.parent}while(t);return e}getAllBindingsOfKind(...e){const t=Object.create(null);for(const r of e){let e=this;do{for(const n of Object.keys(e.bindings)){const s=e.bindings[n];s.kind===r&&(t[n]=s)}e=e.parent}while(e)}return t}bindingIdentifierEquals(e,t){return this.getBindingIdentifier(e)===t}getBinding(e){let t,r=this;do{const s=r.getOwnBinding(e);var n;if(s&&(null==(n=t)||!n.isPattern()||"param"===s.kind))return s;t=r.path}while(r=r.parent)}getOwnBinding(e){return this.bindings[e]}getBindingIdentifier(e){var t;return null==(t=this.getBinding(e))?void 0:t.identifier}getOwnBindingIdentifier(e){const t=this.bindings[e];return null==t?void 0:t.identifier}hasOwnBinding(e){return!!this.getOwnBinding(e)}hasBinding(e,t){return!(!e||!this.hasOwnBinding(e)&&!this.parentHasBinding(e,t)&&!this.hasUid(e)&&(t||!f.globals.includes(e))&&(t||!f.contextVariables.includes(e)))}parentHasBinding(e,t){var r;return null==(r=this.parent)?void 0:r.hasBinding(e,t)}moveBindingTo(e,t){const r=this.getBinding(e);r&&(r.scope.removeOwnBinding(e),r.scope=t,t.bindings[e]=r)}removeOwnBinding(e){delete this.bindings[e]}removeBinding(e){var t;null==(t=this.getBinding(e))||t.scope.removeOwnBinding(e);let r=this;do{r.uids[e]&&(r.uids[e]=!1)}while(r=r.parent)}}t.default=f,f.globals=Object.keys(o.builtin),f.contextVariables=["arguments","undefined","Infinity","NaN"]},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,t.default=class{constructor({identifier:e,scope:t,path:r,kind:n}){this.identifier=void 0,this.scope=void 0,this.path=void 0,this.kind=void 0,this.constantViolations=[],this.constant=!0,this.referencePaths=[],this.referenced=!1,this.references=0,this.identifier=e,this.scope=t,this.path=r,this.kind=n,this.clearValue()}deoptValue(){this.clearValue(),this.hasDeoptedValue=!0}setValue(e){this.hasDeoptedValue||(this.hasValue=!0,this.value=e)}clearValue(){this.hasDeoptedValue=!1,this.hasValue=!1,this.value=null}reassign(e){this.constant=!1,-1===this.constantViolations.indexOf(e)&&this.constantViolations.push(e)}reference(e){-1===this.referencePaths.indexOf(e)&&(this.referenced=!0,this.references++,this.referencePaths.push(e))}dereference(){this.references--,this.referenced=!!this.references}}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.needsWhitespace=f,t.needsWhitespaceBefore=function(e,t){return f(e,t,"before")},t.needsWhitespaceAfter=function(e,t){return f(e,t,"after")},t.needsParens=function(e,t,r){return!!t&&(!(!i.isNewExpression(t)||t.callee!==e||!p(e))||u(a,e,t,r))};var n=r(420),s=r(421),i=r(0);function o(e){const t={};function r(e,r){const n=t[e];t[e]=n?function(e,t,s){const i=n(e,t,s);return null==i?r(e,t,s):i}:r}for(const t of Object.keys(e)){const n=i.FLIPPED_ALIAS_KEYS[t];if(n)for(const s of n)r(s,e[t]);else r(t,e[t])}return t}const a=o(s),l=o(n.nodes),c=o(n.list);function u(e,t,r,n){const s=e[t.type];return s?s(t,r,n):null}function p(e){return!!i.isCallExpression(e)||i.isMemberExpression(e)&&p(e.object)}function f(e,t,r){if(!e)return 0;i.isExpressionStatement(e)&&(e=e.expression);let n=u(l,e,t);if(!n){const s=u(c,e,t);if(s)for(let t=0;t{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ImportSpecifier=function(e){"type"!==e.importKind&&"typeof"!==e.importKind||(this.word(e.importKind),this.space()),this.print(e.imported,e),e.local&&e.local.name!==e.imported.name&&(this.space(),this.word("as"),this.space(),this.print(e.local,e))},t.ImportDefaultSpecifier=function(e){this.print(e.local,e)},t.ExportDefaultSpecifier=function(e){this.print(e.exported,e)},t.ExportSpecifier=function(e){this.print(e.local,e),e.exported&&e.local.name!==e.exported.name&&(this.space(),this.word("as"),this.space(),this.print(e.exported,e))},t.ExportNamespaceSpecifier=function(e){this.token("*"),this.space(),this.word("as"),this.space(),this.print(e.exported,e)},t.ExportAllDeclaration=function(e){this.word("export"),this.space(),"type"===e.exportKind&&(this.word("type"),this.space()),this.token("*"),this.space(),this.word("from"),this.space(),this.print(e.source,e),this.printAssertions(e),this.semicolon()},t.ExportNamedDeclaration=function(e){this.format.decoratorsBeforeExport&&n.isClassDeclaration(e.declaration)&&this.printJoin(e.declaration.decorators,e),this.word("export"),this.space(),s.apply(this,arguments)},t.ExportDefaultDeclaration=function(e){this.format.decoratorsBeforeExport&&n.isClassDeclaration(e.declaration)&&this.printJoin(e.declaration.decorators,e),this.word("export"),this.space(),this.word("default"),this.space(),s.apply(this,arguments)},t.ImportDeclaration=function(e){this.word("import"),this.space(),("type"===e.importKind||"typeof"===e.importKind)&&(this.word(e.importKind),this.space());const t=e.specifiers.slice(0);if(null!=t&&t.length){for(;;){const r=t[0];if(!n.isImportDefaultSpecifier(r)&&!n.isImportNamespaceSpecifier(r))break;this.print(t.shift(),e),t.length&&(this.token(","),this.space())}t.length&&(this.token("{"),this.space(),this.printList(t,e),this.space(),this.token("}")),this.space(),this.word("from"),this.space()}var r;this.print(e.source,e),this.printAssertions(e),null!=(r=e.attributes)&&r.length&&(this.space(),this.word("with"),this.space(),this.printList(e.attributes,e)),this.semicolon()},t.ImportAttribute=function(e){this.print(e.key),this.token(":"),this.space(),this.print(e.value)},t.ImportNamespaceSpecifier=function(e){this.token("*"),this.space(),this.word("as"),this.space(),this.print(e.local,e)};var n=r(0);function s(e){if(e.declaration){const t=e.declaration;this.print(t,e),n.isStatement(t)||this.semicolon()}else{"type"===e.exportKind&&(this.word("type"),this.space());const t=e.specifiers.slice(0);let r=!1;for(;;){const s=t[0];if(!n.isExportDefaultSpecifier(s)&&!n.isExportNamespaceSpecifier(s))break;r=!0,this.print(t.shift(),e),t.length&&(this.token(","),this.space())}(t.length||!t.length&&!r)&&(this.token("{"),t.length&&(this.space(),this.printList(t,e),this.space()),this.token("}")),e.source&&(this.space(),this.word("from"),this.space(),this.print(e.source,e),this.printAssertions(e)),this.semicolon()}}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Identifier=function(e){this.exactSource(e.loc,(()=>{this.word(e.name)}))},t.ArgumentPlaceholder=function(){this.token("?")},t.SpreadElement=t.RestElement=function(e){this.token("..."),this.print(e.argument,e)},t.ObjectPattern=t.ObjectExpression=function(e){const t=e.properties;this.token("{"),this.printInnerComments(e),t.length&&(this.space(),this.printList(t,e,{indent:!0,statement:!0}),this.space()),this.token("}")},t.ObjectMethod=function(e){this.printJoin(e.decorators,e),this._methodHead(e),this.space(),this.print(e.body,e)},t.ObjectProperty=function(e){if(this.printJoin(e.decorators,e),e.computed)this.token("["),this.print(e.key,e),this.token("]");else{if(n.isAssignmentPattern(e.value)&&n.isIdentifier(e.key)&&e.key.name===e.value.left.name)return void this.print(e.value,e);if(this.print(e.key,e),e.shorthand&&n.isIdentifier(e.key)&&n.isIdentifier(e.value)&&e.key.name===e.value.name)return}this.token(":"),this.space(),this.print(e.value,e)},t.ArrayPattern=t.ArrayExpression=function(e){const t=e.elements,r=t.length;this.token("["),this.printInnerComments(e);for(let n=0;n0&&this.space(),this.print(s,e),n0&&this.space(),this.print(s,e),n{"use strict";var n=r(37).Buffer;const s={},i=s.hasOwnProperty,o=(e,t)=>{for(const r in e)i.call(e,r)&&t(r,e[r])},a=s.toString,l=Array.isArray,c=n.isBuffer,u={'"':'\\"',"'":"\\'","\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"},p=/["'\\\b\f\n\r\t]/,f=/[0-9]/,d=/[ !#-&\(-\[\]-_a-~]/,h=(e,t)=>{const r=()=>{E=v,++t.indentLevel,v=t.indent.repeat(t.indentLevel)},n={escapeEverything:!1,minimal:!1,isScriptContext:!1,quotes:"single",wrap:!1,es6:!1,json:!1,compact:!0,lowercaseHex:!1,numbers:"decimal",indent:"\t",indentLevel:0,__inline1__:!1,__inline2__:!1},s=t&&t.json;var i,m;s&&(n.quotes="double",n.wrap=!0),i=n,"single"!=(t=(m=t)?(o(m,((e,t)=>{i[e]=t})),i):i).quotes&&"double"!=t.quotes&&"backtick"!=t.quotes&&(t.quotes="single");const y="double"==t.quotes?'"':"backtick"==t.quotes?"`":"'",g=t.compact,b=t.lowercaseHex;let v=t.indent.repeat(t.indentLevel),E="";const x=t.__inline1__,S=t.__inline2__,T=g?"":"\n";let w,P=!0;const A="binary"==t.numbers,O="octal"==t.numbers,C="decimal"==t.numbers,I="hexadecimal"==t.numbers;if(s&&e&&"function"==typeof e.toJSON&&(e=e.toJSON()),"string"!=typeof(k=e)&&"[object String]"!=a.call(k)){if((e=>"[object Map]"==a.call(e))(e))return 0==e.size?"new Map()":(g||(t.__inline1__=!0,t.__inline2__=!1),"new Map("+h(Array.from(e),t)+")");if((e=>"[object Set]"==a.call(e))(e))return 0==e.size?"new Set()":"new Set("+h(Array.from(e),t)+")";if(c(e))return 0==e.length?"Buffer.from([])":"Buffer.from("+h(Array.from(e),t)+")";if(l(e))return w=[],t.wrap=!0,x&&(t.__inline1__=!1,t.__inline2__=!0),S||r(),((e,t)=>{const r=e.length;let n=-1;for(;++n{P=!1,S&&(t.__inline2__=!1),w.push((g||S?"":v)+h(e,t))})),P?"[]":S?"["+w.join(", ")+"]":"["+T+w.join(","+T)+T+(g?"":E)+"]";if(!(e=>"number"==typeof e||"[object Number]"==a.call(e))(e))return(e=>"[object Object]"==a.call(e))(e)?(w=[],t.wrap=!0,r(),o(e,((e,r)=>{P=!1,w.push((g?"":v)+h(e,t)+":"+(g?"":" ")+h(r,t))})),P?"{}":"{"+T+w.join(","+T)+T+(g?"":E)+"}"):s?JSON.stringify(e)||"null":String(e);if(s)return JSON.stringify(e);if(C)return String(e);if(I){let t=e.toString(16);return b||(t=t.toUpperCase()),"0x"+t}if(A)return"0b"+e.toString(2);if(O)return"0o"+e.toString(8)}var k;const N=e;let _=-1;const j=N.length;for(w="";++_=55296&&e<=56319&&j>_+1){const t=N.charCodeAt(_+1);if(t>=56320&&t<=57343){let r=(1024*(e-55296)+t-56320+65536).toString(16);b||(r=r.toUpperCase()),w+="\\u{"+r+"}",++_;continue}}}if(!t.escapeEverything){if(d.test(e)){w+=e;continue}if('"'==e){w+=y==e?'\\"':e;continue}if("`"==e){w+=y==e?"\\`":e;continue}if("'"==e){w+=y==e?"\\'":e;continue}}if("\0"==e&&!s&&!f.test(N.charAt(_+1))){w+="\\0";continue}if(p.test(e)){w+=u[e];continue}const r=e.charCodeAt(0);if(t.minimal&&8232!=r&&8233!=r){w+=e;continue}let n=r.toString(16);b||(n=n.toUpperCase());const i=n.length>2||s,o="\\"+(i?"u":"x")+("0000"+n).slice(i?-4:-2);w+=o}return t.wrap&&(w=y+w+y),"`"==y&&(w=w.replace(/\$\{/g,"\\${")),t.isScriptContext?w.replace(/<\/(script|style)/gi,"<\\/$1").replace(/|--!>|O(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,r])=>(e[`${t} =>`]=r,e)),{})}:C(t)?{[`Set(${t.size})`]:[...t.values()]}:!_(t)||A(t)||L(t)?t:String(t),T=/^on[^a-z]/,w=Object.assign,P=Object.prototype.hasOwnProperty,A=Array.isArray,O=e=>"[object Map]"===D(e),C=e=>"[object Set]"===D(e),I=e=>e instanceof Date,k=e=>"function"==typeof e,N=e=>"string"==typeof e,_=e=>null!==e&&"object"==typeof e,j=Object.prototype.toString,D=e=>j.call(e),L=e=>"[object Object]"===D(e),M=n(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),B=e=>{const t=Object.create(null);return r=>t[r]||(t[r]=e(r))},R=/-(\w)/g,F=B((e=>e.replace(R,((e,t)=>t?t.toUpperCase():"")))),U=/\B([A-Z])/g,$=B((e=>e.replace(U,"-$1").toLowerCase())),q=B((e=>e.charAt(0).toUpperCase()+e.slice(1))),V=B((e=>e?`on${q(e)}`:""));let W;t.EMPTY_ARR=[],t.EMPTY_OBJ={},t.NO=()=>!1,t.NOOP=()=>{},t.PatchFlagNames=s,t.babelParserDefaultPlugins=["bigInt","optionalChaining","nullishCoalescingOperator"],t.camelize=F,t.capitalize=q,t.def=(e,t,r)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:r})},t.escapeHtml=function(e){const t=""+e,r=v.exec(t);if(!r)return t;let n,s,i="",o=0;for(s=r.index;s=t){for(let o=e-2;o<=e+2||r>s;o++){if(o<0||o>=n.length)continue;const a=o+1;i.push(`${a}${" ".repeat(Math.max(3-String(a).length,0))}| ${n[o]}`);const l=n[o].length;if(o===e){const e=t-(s-l)+1,n=Math.max(1,r>s?l-e:r-t);i.push(" | "+" ".repeat(e)+"^".repeat(n))}else if(o>e){if(r>s){const e=Math.max(Math.min(r-s,l),1);i.push(" | "+"^".repeat(e))}s+=l+1}}break}return i.join("\n")},t.getGlobalThis=()=>W||(W="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==r.g?r.g:{}),t.hasChanged=(e,t)=>e!==t&&(e==e||t==t),t.hasOwn=(e,t)=>P.call(e,t),t.hyphenate=$,t.invokeArrayFns=(e,t)=>{for(let r=0;rN(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,t.isKnownAttr=f,t.isMap=O,t.isModelListener=e=>e.startsWith("onUpdate:"),t.isNoUnitNumericStyleProp=p,t.isObject=_,t.isOn=e=>T.test(e),t.isPlainObject=L,t.isPromise=e=>_(e)&&k(e.then)&&k(e.catch),t.isReservedProp=M,t.isSSRSafeAttrName=function(e){if(u.hasOwnProperty(e))return u[e];const t=c.test(e);return u[e]=!t},t.isSVGTag=g,t.isSet=C,t.isSpecialBooleanAttr=a,t.isString=N,t.isSymbol=e=>"symbol"==typeof e,t.isVoidTag=b,t.looseEqual=x,t.looseIndexOf=function(e,t){return e.findIndex((e=>x(e,t)))},t.makeMap=n,t.normalizeClass=function e(t){let r="";if(N(t))r=t;else if(A(t))for(let n=0;n{const r=e.indexOf(t);r>-1&&e.splice(r,1)},t.slotFlagsText={1:"STABLE",2:"DYNAMIC",3:"FORWARDED"},t.stringifyStyle=function(e){let t="";if(!e)return t;for(const r in e){const n=e[r],s=r.startsWith("--")?r:$(r);(N(n)||"number"==typeof n&&p(s))&&(t+=`${s}:${n};`)}return t},t.toDisplayString=e=>null==e?"":_(e)?JSON.stringify(e,S,2):String(e),t.toHandlerKey=V,t.toNumber=e=>{const t=parseFloat(e);return isNaN(t)?e:t},t.toRawType=e=>D(e).slice(8,-1),t.toTypeString=D},()=>{},()=>{},(e,t,r)=>{"use strict";var n=r(168),s=r(307);function i(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}t.parse=v,t.resolve=function(e,t){return v(e,!1,!0).resolve(t)},t.resolveObject=function(e,t){return e?v(e,!1,!0).resolveObject(t):t},t.format=function(e){return s.isString(e)&&(e=v(e)),e instanceof i?e.format():i.prototype.format.call(e)},t.Url=i;var o=/^([a-z0-9.+-]+:)/i,a=/:[0-9]*$/,l=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,c=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),u=["'"].concat(c),p=["%","/","?",";","#"].concat(u),f=["/","?","#"],d=/^[+a-z0-9A-Z_-]{0,63}$/,h=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},y={javascript:!0,"javascript:":!0},g={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},b=r(511);function v(e,t,r){if(e&&s.isObject(e)&&e instanceof i)return e;var n=new i;return n.parse(e,t,r),n}i.prototype.parse=function(e,t,r){if(!s.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var i=e.indexOf("?"),a=-1!==i&&i127?j+="x":j+=_[D];if(!j.match(d)){var M=k.slice(0,O),B=k.slice(O+1),R=_.match(h);R&&(M.push(R[1]),B.unshift(R[2])),B.length&&(v="/"+B.join(".")+v),this.hostname=M.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),I||(this.hostname=n.toASCII(this.hostname));var F=this.port?":"+this.port:"",U=this.hostname||"";this.host=U+F,this.href+=this.host,I&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==v[0]&&(v="/"+v))}if(!m[S])for(O=0,N=u.length;O0)&&r.host.split("@"))&&(r.auth=I.shift(),r.host=r.hostname=I.shift())),r.search=e.search,r.query=e.query,s.isNull(r.pathname)&&s.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r;if(!T.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var P=T.slice(-1)[0],A=(r.host||e.host||T.length>1)&&("."===P||".."===P)||""===P,O=0,C=T.length;C>=0;C--)"."===(P=T[C])?T.splice(C,1):".."===P?(T.splice(C,1),O++):O&&(T.splice(C,1),O--);if(!x&&!S)for(;O--;O)T.unshift("..");!x||""===T[0]||T[0]&&"/"===T[0].charAt(0)||T.unshift(""),A&&"/"!==T.join("/").substr(-1)&&T.push("");var I,k=""===T[0]||T[0]&&"/"===T[0].charAt(0);return w&&(r.hostname=r.host=k?"":T.length?T.shift():"",(I=!!(r.host&&r.host.indexOf("@")>0)&&r.host.split("@"))&&(r.auth=I.shift(),r.host=r.hostname=I.shift())),(x=x||r.host&&T.length)&&!k&&T.unshift(""),T.length?r.pathname=T.join("/"):(r.pathname=null,r.path=null),s.isNull(r.pathname)&&s.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r},i.prototype.parseHost=function(){var e=this.host,t=a.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},(e,t,r)=>{"use strict";t.decode=t.parse=r(317),t.encode=t.stringify=r(318)},()=>{},()=>{},()=>{},(e,t,r)=>{"use strict";t.__esModule=!0,t.default=function(e){var t,r,n,s,o,a,l,c,u,p,d,h,m=[],y=e.css.valueOf(),g=y.length,b=-1,v=1,E=0,x=0;function S(t,r){if(!e.safe)throw e.error("Unclosed "+t,v,E-b,E);c=(y+=r).length-1}for(;E0?(u=v+a,p=c-l[a].length):(u=v,p=b),h=i.comment,v=u,n=u,r=c-p):t===i.slash?(h=t,n=v,r=E-b,x=(c=E)+1):(c=f(y,E),h=i.word,n=v,r=c-b),x=c+1}m.push([h,v,E-b,n,r,E,x]),p&&(b=p,p=null),E=x}return m},t.FIELDS=void 0;var n,s,i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if(Object.prototype.hasOwnProperty.call(e,s)){var i=n?Object.getOwnPropertyDescriptor(e,s):null;i&&(i.get||i.set)?Object.defineProperty(r,s,i):r[s]=e[s]}return r.default=e,t&&t.set(e,r),r}(r(328));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}for(var a=((n={})[i.tab]=!0,n[i.newline]=!0,n[i.cr]=!0,n[i.feed]=!0,n),l=((s={})[i.space]=!0,s[i.tab]=!0,s[i.newline]=!0,s[i.cr]=!0,s[i.feed]=!0,s[i.ampersand]=!0,s[i.asterisk]=!0,s[i.bang]=!0,s[i.comma]=!0,s[i.colon]=!0,s[i.semicolon]=!0,s[i.openParenthesis]=!0,s[i.closeParenthesis]=!0,s[i.openSquare]=!0,s[i.closeSquare]=!0,s[i.singleQuote]=!0,s[i.doubleQuote]=!0,s[i.plus]=!0,s[i.pipe]=!0,s[i.tilde]=!0,s[i.greaterThan]=!0,s[i.equals]=!0,s[i.dollar]=!0,s[i.caret]=!0,s[i.slash]=!0,s),c={},u="0123456789abcdefABCDEF",p=0;p{"use strict";t.__esModule=!0,t.universal=t.tag=t.string=t.selector=t.root=t.pseudo=t.nesting=t.id=t.comment=t.combinator=t.className=t.attribute=void 0;var n=m(r(326)),s=m(r(100)),i=m(r(107)),o=m(r(101)),a=m(r(102)),l=m(r(108)),c=m(r(105)),u=m(r(97)),p=m(r(99)),f=m(r(104)),d=m(r(103)),h=m(r(106));function m(e){return e&&e.__esModule?e:{default:e}}t.attribute=function(e){return new n.default(e)},t.className=function(e){return new s.default(e)},t.combinator=function(e){return new i.default(e)},t.comment=function(e){return new o.default(e)},t.id=function(e){return new a.default(e)},t.nesting=function(e){return new l.default(e)},t.pseudo=function(e){return new c.default(e)},t.root=function(e){return new u.default(e)},t.selector=function(e){return new p.default(e)},t.string=function(e){return new f.default(e)},t.tag=function(e){return new d.default(e)},t.universal=function(e){return new h.default(e)}},(e,t,r)=>{"use strict";t.__esModule=!0,t.isNode=o,t.isPseudoElement=E,t.isPseudoClass=function(e){return h(e)&&!E(e)},t.isContainer=function(e){return!(!o(e)||!e.walk)},t.isNamespace=function(e){return l(e)||b(e)},t.isUniversal=t.isTag=t.isString=t.isSelector=t.isRoot=t.isPseudo=t.isNesting=t.isIdentifier=t.isComment=t.isCombinator=t.isClassName=t.isAttribute=void 0;var n,s=r(5),i=((n={})[s.ATTRIBUTE]=!0,n[s.CLASS]=!0,n[s.COMBINATOR]=!0,n[s.COMMENT]=!0,n[s.ID]=!0,n[s.NESTING]=!0,n[s.PSEUDO]=!0,n[s.ROOT]=!0,n[s.SELECTOR]=!0,n[s.STRING]=!0,n[s.TAG]=!0,n[s.UNIVERSAL]=!0,n);function o(e){return"object"==typeof e&&i[e.type]}function a(e,t){return o(t)&&t.type===e}var l=a.bind(null,s.ATTRIBUTE);t.isAttribute=l;var c=a.bind(null,s.CLASS);t.isClassName=c;var u=a.bind(null,s.COMBINATOR);t.isCombinator=u;var p=a.bind(null,s.COMMENT);t.isComment=p;var f=a.bind(null,s.ID);t.isIdentifier=f;var d=a.bind(null,s.NESTING);t.isNesting=d;var h=a.bind(null,s.PSEUDO);t.isPseudo=h;var m=a.bind(null,s.ROOT);t.isRoot=m;var y=a.bind(null,s.SELECTOR);t.isSelector=y;var g=a.bind(null,s.STRING);t.isString=g;var b=a.bind(null,s.TAG);t.isTag=b;var v=a.bind(null,s.UNIVERSAL);function E(e){return h(e)&&e.value&&(e.value.startsWith("::")||":before"===e.value.toLowerCase()||":after"===e.value.toLowerCase())}t.isUniversal=v},()=>{},()=>{},()=>{},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.replaceAll=n;var r=/[$#]?[\w-\.]+/g;function n(e,t){for(var n=void 0;n=r.exec(t);){var s=e[n[0]];s&&(t=t.slice(0,n.index)+s+t.slice(r.lastIndex),r.lastIndex-=n[0].length-s.length)}return t}t.default=function(e,t){e.walkDecls((function(e){return e.value=n(t,e.value)})),e.walkAtRules("media",(function(e){return e.params=n(t,e.params)}))}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=a(r(84)),s=a(r(523)),i=a(r(8)),o=a(r(332));function a(e){return e&&e.__esModule?e:{default:e}}class l{constructor(e){this.plugins=e||l.defaultPlugins}load(e,t,r,s){let i=new o.default(s,r);return(0,n.default)(this.plugins.concat([i.plugin()])).process(e,{from:"/"+t}).then((e=>({injectableSource:e.css,exportTokens:i.exportTokens})))}}const c=(e,t)=>e.lengtht.length?e.substring(0,t.length)<=t?-1:1:e{let l=i.default.dirname(t),c=i.default.resolve(l,o),u=i.default.resolve(i.default.join(this.root,l),o);if("."!==o[0]&&"/"!==o[0])try{u=r(524).resolve(o)}catch(e){}const p=this.tokensByFile[u];if(p)return e(p);s.default.readFile(u,"utf-8",((t,r)=>{t&&n(t),this.core.load(r,c,a,this.fetch.bind(this)).then((({injectableSource:t,exportTokens:r})=>{this.sources[u]=t,this.traces[a]=u,this.tokensByFile[u]=r,e(r)}),n)}))}))}get finalSource(){const e=this.traces,t=this.sources;let r=new Set;return Object.keys(e).sort(c).map((n=>{const s=e[n];return r.has(s)?null:(r.add(s),t[s])})).join("")}}},()=>{},e=>{function t(e){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=524,e.exports=t},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,r){const n=r.indexOf(`.${e}`),i=r.substr(0,n).split(/[\r\n]/).length;return`_${e}_${(0,s.default)(r).toString(36).substr(0,5)}_${i}`};var n,s=(n=r(333))&&n.__esModule?n:{default:n}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){return new Promise(((r,s)=>{(0,n.writeFile)(`${e}.json`,JSON.stringify(t),(e=>e?s(e):r(t)))}))};var n=r(527)},()=>{},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.behaviours=void 0,t.getDefaultPlugins=function({behaviour:e,generateScopedName:t,exportGlobals:r}){const a=(0,i.default)({generateScopedName:t,exportGlobals:r});return{[l.LOCAL]:[o.default,n.default,s.default,a],[l.GLOBAL]:[o.default,s.default,a]}[e]},t.isValidBehaviour=function(e){return Object.keys(l).map((e=>l[e])).indexOf(e)>-1};var n=a(r(334)),s=a(r(344)),i=a(r(529)),o=a(r(530));function a(e){return e&&e.__esModule?e:{default:e}}const l=t.behaviours={LOCAL:"local",GLOBAL:"global"}},()=>{},()=>{},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-jsx",manipulateOptions(e,t){t.plugins.some((e=>"typescript"===(Array.isArray(e)?e[0]:e)))||t.plugins.push("jsx")}})));t.default=n},(e,t,r)=>{"use strict";e.exports=r(533)},e=>{"use strict";e.exports=JSON.parse('["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","label","legend","li","link","main","map","mark","math","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rb","rp","rt","rtc","ruby","s","samp","script","section","select","slot","small","source","span","strong","style","sub","summary","sup","svg","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr"]')},(e,t,r)=>{e.exports=r(535)},e=>{"use strict";e.exports=JSON.parse('["a","altGlyph","altGlyphDef","altGlyphItem","animate","animateColor","animateMotion","animateTransform","circle","clipPath","color-profile","cursor","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","font","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignObject","g","glyph","glyphRef","hkern","image","line","linearGradient","marker","mask","metadata","missing-glyph","mpath","path","pattern","polygon","polyline","radialGradient","rect","script","set","stop","style","svg","switch","symbol","text","textPath","title","tref","tspan","use","view","vkern"]')},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-class-static-block",manipulateOptions(e,t){t.plugins.push("classStaticBlock")}})));t.default=n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.buildPrivateNamesMap=function(e){const t=new Map;for(const r of e){const e=r.isPrivate(),n=!r.isProperty(),s=!r.node.static;if(e){const{name:e}=r.node.key.id,i=t.has(e)?t.get(e):{id:r.scope.generateUidIdentifier(e),static:!s,method:n};"get"===r.node.kind?i.getId=r.scope.generateUidIdentifier(`get_${e}`):"set"===r.node.kind?i.setId=r.scope.generateUidIdentifier(`set_${e}`):"method"===r.node.kind&&(i.methodId=r.scope.generateUidIdentifier(e)),t.set(e,i)}}return t},t.buildPrivateNamesNodes=function(e,t,r){const s=[];for(const[i,o]of e){const{static:e,method:l,getId:c,setId:u}=o,p=c||u,f=n.types.cloneNode(o.id);let d;t?d=n.types.callExpression(r.addHelper("classPrivateFieldLooseKey"),[n.types.stringLiteral(i)]):e||(d=n.types.newExpression(n.types.identifier(!l||p?"WeakMap":"WeakSet"),[])),d&&((0,a.default)(d),s.push(n.template.statement.ast`var ${f} = ${d}`))}return s},t.transformPrivateNamesUsage=function(e,t,r,{privateFieldsAsProperties:n,noDocumentAll:s},o){if(!r.size)return;const a=t.get("body"),l=n?d:f;(0,i.default)(a,u,Object.assign({privateNamesMap:r,classRef:e,file:o},l,{noDocumentAll:s})),a.traverse(p,{privateNamesMap:r,classRef:e,file:o,privateFieldsAsProperties:n})},t.buildFieldsInitNodes=function(e,t,r,s,i,o,a,c,u){let p,f=!1;const d=[],T=[],w=[],A=n.types.isIdentifier(t)?()=>t:()=>(null!=p||(p=r[0].scope.generateUidIdentifierBasedOnNode(t)),p);for(const t of r){l.assertFieldTransformed(t);const r=t.node.static,p=!r,O=t.isPrivate(),C=!O,I=t.isProperty(),k=!I,N=null==t.isStaticBlock?void 0:t.isStaticBlock();if(r||k&&O||N){const r=P(t,e,A,i,N,c,u);f=f||r}switch(!0){case N:d.push(n.template.statement.ast`(() => ${n.types.blockStatement(t.node.body)})()`);break;case r&&O&&I&&a:f=!0,d.push(h(n.types.cloneNode(e),t,s));break;case r&&O&&I&&!a:f=!0,d.push(y(t,s));break;case r&&C&&I&&o:f=!0,d.push(v(n.types.cloneNode(e),t));break;case r&&C&&I&&!o:f=!0,d.push(E(n.types.cloneNode(e),t,i));break;case p&&O&&I&&a:T.push(h(n.types.thisExpression(),t,s));break;case p&&O&&I&&!a:T.push(m(n.types.thisExpression(),t,s));break;case p&&O&&k&&a:T.unshift(g(n.types.thisExpression(),t,s)),w.push(S(t,s,a));break;case p&&O&&k&&!a:T.unshift(b(n.types.thisExpression(),t,s)),w.push(S(t,s,a));break;case r&&O&&k&&!a:f=!0,d.unshift(y(t,s)),w.push(S(t,s,a));break;case r&&O&&k&&a:f=!0,d.unshift(x(n.types.cloneNode(e),t,0,s)),w.push(S(t,s,a));break;case p&&C&&I&&o:T.push(v(n.types.thisExpression(),t));break;case p&&C&&I&&!o:T.push(E(n.types.thisExpression(),t,i));break;default:throw new Error("Unreachable.")}}return{staticNodes:d.filter(Boolean),instanceNodes:T.filter(Boolean),pureStaticNodes:w.filter(Boolean),wrapClass(t){for(const e of r)e.remove();return p&&(t.scope.push({id:n.types.cloneNode(p)}),t.set("superClass",n.types.assignmentExpression("=",p,t.node.superClass))),f?(t.isClassExpression()?(t.scope.push({id:e}),t.replaceWith(n.types.assignmentExpression("=",n.types.cloneNode(e),t.node))):t.node.id||(t.node.id=e),t):t}}};var n=r(9),s=r(70),i=r(258),o=r(259),a=r(347),l=r(538);function c(e){const t=Object.assign({},e,{Class(e){const{privateNamesMap:n}=this,s=e.get("body.body"),i=new Map(n),o=[];for(const e of s){if(!e.isPrivate())continue;const{name:t}=e.node.key.id;i.delete(t),o.push(t)}o.length&&(e.get("body").traverse(r,Object.assign({},this,{redeclared:o})),e.traverse(t,Object.assign({},this,{privateNamesMap:i})),e.skipKey("body"))}}),r=n.traverse.visitors.merge([Object.assign({},e),s.environmentVisitor]);return t}const u=c({PrivateName(e,{noDocumentAll:t}){const{privateNamesMap:r,redeclared:n}=this,{node:s,parentPath:i}=e;if(!i.isMemberExpression({property:s})&&!i.isOptionalMemberExpression({property:s}))return;const{name:o}=s.id;r.has(o)&&(n&&n.includes(o)||this.handle(i,t))}}),p=c({BinaryExpression(e){const{operator:t,left:r,right:s}=e.node;if("in"!==t)return;if(!e.get("left").isPrivateName())return;const{privateFieldsAsProperties:i,privateNamesMap:o,redeclared:a}=this,{name:l}=r.id;if(!o.has(l))return;if(a&&a.includes(l))return;if(i){const{id:t}=o.get(l);return void e.replaceWith(n.template.expression.ast` Object.prototype.hasOwnProperty.call(${s}, ${n.types.cloneNode(t)}) `)}const{id:c,static:u}=o.get(l);u?e.replaceWith(n.template.expression.ast`${s} === ${this.classRef}`):e.replaceWith(n.template.expression.ast`${n.types.cloneNode(c)}.has(${s})`)}}),f={memoise(e,t){const{scope:r}=e,{object:n}=e.node,s=r.maybeGenerateMemoised(n);s&&this.memoiser.set(n,s,t)},receiver(e){const{object:t}=e.node;return this.memoiser.has(t)?n.types.cloneNode(this.memoiser.get(t)):n.types.cloneNode(t)},get(e){const{classRef:t,privateNamesMap:r,file:s}=this,{name:i}=e.node.property.id,{id:o,static:a,method:l,methodId:c,getId:u,setId:p}=r.get(i),f=u||p;if(a){const r=l&&!f?"classStaticPrivateMethodGet":"classStaticPrivateFieldSpecGet";return n.types.callExpression(s.addHelper(r),[this.receiver(e),n.types.cloneNode(t),n.types.cloneNode(o)])}return l?f?!u&&p&&s.availableHelper("writeOnlyError")?n.types.sequenceExpression([this.receiver(e),n.types.callExpression(s.addHelper("writeOnlyError"),[n.types.stringLiteral(`#${i}`)])]):n.types.callExpression(s.addHelper("classPrivateFieldGet"),[this.receiver(e),n.types.cloneNode(o)]):n.types.callExpression(s.addHelper("classPrivateMethodGet"),[this.receiver(e),n.types.cloneNode(o),n.types.cloneNode(c)]):n.types.callExpression(s.addHelper("classPrivateFieldGet"),[this.receiver(e),n.types.cloneNode(o)])},boundGet(e){return this.memoise(e,1),n.types.callExpression(n.types.memberExpression(this.get(e),n.types.identifier("bind")),[this.receiver(e)])},set(e,t){const{classRef:r,privateNamesMap:s,file:i}=this,{name:o}=e.node.property.id,{id:a,static:l,method:c,setId:u,getId:p}=s.get(o);if(l){const s=!c||p||u?"classStaticPrivateFieldSpecSet":"classStaticPrivateMethodSet";return n.types.callExpression(i.addHelper(s),[this.receiver(e),n.types.cloneNode(r),n.types.cloneNode(a),t])}return c?u?n.types.callExpression(i.addHelper("classPrivateFieldSet"),[this.receiver(e),n.types.cloneNode(a),t]):n.types.sequenceExpression([this.receiver(e),t,n.types.callExpression(i.addHelper("readOnlyError"),[n.types.stringLiteral(`#${o}`)])]):n.types.callExpression(i.addHelper("classPrivateFieldSet"),[this.receiver(e),n.types.cloneNode(a),t])},destructureSet(e){const{classRef:t,privateNamesMap:r,file:s}=this,{name:i}=e.node.property.id,{id:o,static:a}=r.get(i);if(a){try{var l=s.addHelper("classStaticPrivateFieldDestructureSet")}catch(e){throw new Error("Babel can not transpile `[C.#p] = [0]` with @babel/helpers < 7.13.10, \nplease update @babel/helpers to the latest version.")}return n.types.memberExpression(n.types.callExpression(l,[this.receiver(e),n.types.cloneNode(t),n.types.cloneNode(o)]),n.types.identifier("value"))}return n.types.memberExpression(n.types.callExpression(s.addHelper("classPrivateFieldDestructureSet"),[this.receiver(e),n.types.cloneNode(o)]),n.types.identifier("value"))},call(e,t){return this.memoise(e,1),(0,o.default)(this.get(e),this.receiver(e),t,!1)},optionalCall(e,t){return this.memoise(e,1),(0,o.default)(this.get(e),this.receiver(e),t,!0)}},d={get(e){const{privateNamesMap:t,file:r}=this,{object:s}=e.node,{name:i}=e.node.property.id;return n.template.expression`BASE(REF, PROP)[PROP]`({BASE:r.addHelper("classPrivateFieldLooseBase"),REF:n.types.cloneNode(s),PROP:n.types.cloneNode(t.get(i).id)})},boundGet(e){return n.types.callExpression(n.types.memberExpression(this.get(e),n.types.identifier("bind")),[n.types.cloneNode(e.node.object)])},simpleSet(e){return this.get(e)},destructureSet(e){return this.get(e)},call(e,t){return n.types.callExpression(this.get(e),t)},optionalCall(e,t){return n.types.optionalCallExpression(this.get(e),t,!0)}};function h(e,t,r){const{id:s}=r.get(t.node.key.id.name),i=t.node.value||t.scope.buildUndefinedNode();return n.template.statement.ast` Object.defineProperty(${e}, ${n.types.cloneNode(s)}, { // configurable is false by default // enumerable is false by default writable: true, value: ${i} }); `}function m(e,t,r){const{id:s}=r.get(t.node.key.id.name),i=t.node.value||t.scope.buildUndefinedNode();return n.template.statement.ast`${n.types.cloneNode(s)}.set(${e}, { // configurable is always false for private elements // enumerable is always false for private elements writable: true, value: ${i}, })`}function y(e,t){const r=t.get(e.node.key.id.name),{id:s,getId:i,setId:o,initAdded:a}=r,l=i||o;if(!e.isProperty()&&(a||!l))return;if(l)return t.set(e.node.key.id.name,Object.assign({},r,{initAdded:!0})),n.template.statement.ast` var ${n.types.cloneNode(s)} = { // configurable is false by default // enumerable is false by default // writable is false by default get: ${i?i.name:e.scope.buildUndefinedNode()}, set: ${o?o.name:e.scope.buildUndefinedNode()} } `;const c=e.node.value||e.scope.buildUndefinedNode();return n.template.statement.ast` var ${n.types.cloneNode(s)} = { // configurable is false by default // enumerable is false by default writable: true, value: ${c} }; `}function g(e,t,r){const s=r.get(t.node.key.id.name),{methodId:i,id:o,getId:a,setId:l,initAdded:c}=s;if(!c)return i?n.template.statement.ast` Object.defineProperty(${e}, ${o}, { // configurable is false by default // enumerable is false by default // writable is false by default value: ${i.name} }); `:a||l?(r.set(t.node.key.id.name,Object.assign({},s,{initAdded:!0})),n.template.statement.ast` Object.defineProperty(${e}, ${o}, { // configurable is false by default // enumerable is false by default // writable is false by default get: ${a?a.name:t.scope.buildUndefinedNode()}, set: ${l?l.name:t.scope.buildUndefinedNode()} }); `):void 0}function b(e,t,r){const s=r.get(t.node.key.id.name),{id:i,getId:o,setId:a,initAdded:l}=s;if(!l)return o||a?(r.set(t.node.key.id.name,Object.assign({},s,{initAdded:!0})),n.template.statement.ast` ${i}.set(${e}, { get: ${o?o.name:t.scope.buildUndefinedNode()}, set: ${a?a.name:t.scope.buildUndefinedNode()} }); `):n.template.statement.ast`${i}.add(${e})`}function v(e,t){const{key:r,computed:s}=t.node,i=t.node.value||t.scope.buildUndefinedNode();return n.types.expressionStatement(n.types.assignmentExpression("=",n.types.memberExpression(e,r,s||n.types.isLiteral(r)),i))}function E(e,t,r){const{key:s,computed:i}=t.node,o=t.node.value||t.scope.buildUndefinedNode();return n.types.expressionStatement(n.types.callExpression(r.addHelper("defineProperty"),[e,i||n.types.isLiteral(s)?s:n.types.stringLiteral(s.name),o]))}function x(e,t,r,s){const i=s.get(t.node.key.id.name),{id:o,methodId:a,getId:l,setId:c,initAdded:u}=i;if(!u)return l||c?(s.set(t.node.key.id.name,Object.assign({},i,{initAdded:!0})),n.template.statement.ast` Object.defineProperty(${e}, ${o}, { // configurable is false by default // enumerable is false by default // writable is false by default get: ${l?l.name:t.scope.buildUndefinedNode()}, set: ${c?c.name:t.scope.buildUndefinedNode()} }) `):n.template.statement.ast` Object.defineProperty(${e}, ${o}, { // configurable is false by default // enumerable is false by default // writable is false by default value: ${a.name} }); `}function S(e,t,r=!1){const s=t.get(e.node.key.id.name),{id:i,methodId:o,getId:a,setId:l,getterDeclared:c,setterDeclared:u,static:p}=s,{params:f,body:d,generator:h,async:m}=e.node,y=a&&!c&&0===f.length,g=l&&!u&&f.length>0;let b=o;return y?(t.set(e.node.key.id.name,Object.assign({},s,{getterDeclared:!0})),b=a):g?(t.set(e.node.key.id.name,Object.assign({},s,{setterDeclared:!0})),b=l):p&&!r&&(b=i),n.types.functionDeclaration(n.types.cloneNode(b),f,d,h,m)}const T=n.traverse.visitors.merge([{ThisExpression(e,t){t.needsClassRef=!0,e.replaceWith(n.types.cloneNode(t.classRef))}},s.environmentVisitor]),w={ReferencedIdentifier(e,t){e.scope.bindingIdentifierEquals(e.node.name,t.innerBinding)&&(t.needsClassRef=!0,e.node.name=t.classRef.name)}};function P(e,t,r,i,o,a,l){var c;const u={classRef:t,needsClassRef:!1,innerBinding:l};return new s.default({methodPath:e,constantSuper:a,file:i,refToPreserve:t,getSuperRef:r,getObjectRef:()=>(u.needsClassRef=!0,o||e.node.static?t:n.types.memberExpression(t,n.types.identifier("prototype")))}).replace(),(o||e.isProperty())&&e.traverse(T,u),null!=(c=u.classRef)&&c.name&&u.classRef.name!==(null==l?void 0:l.name)&&e.traverse(w,u),u.needsClassRef}},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.assertFieldTransformed=function(e){if(e.node.declare)throw e.buildCodeFrameError("TypeScript 'declare' fields must first be transformed by @babel/plugin-transform-typescript.\nIf you have already enabled that plugin (or '@babel/preset-typescript'), make sure that it runs before any plugin related to additional class features:\n - @babel/plugin-proposal-class-properties\n - @babel/plugin-proposal-private-methods\n - @babel/plugin-proposal-decorators")}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.injectInitialization=function(e,t,r,s){if(!r.length)return;const a=!!e.node.superClass;if(!t){const r=n.types.classMethod("constructor",n.types.identifier("constructor"),[],n.types.blockStatement([]));a&&(r.params=[n.types.restElement(n.types.identifier("args"))],r.body.body.push(n.template.statement.ast`super(...args)`)),[t]=e.get("body").unshiftContainer("body",r)}if(s&&s(o,{scope:t.scope}),a){const e=[];t.traverse(i,e);let s=!0;for(const t of e)s?(t.insertAfter(r),s=!1):t.insertAfter(r.map((e=>n.types.cloneNode(e))))}else t.get("body").unshiftContainer("body",r)},t.extractComputedKeys=function(e,t,r,s){const i=[],o={classBinding:t.node.id&&t.scope.getBinding(t.node.id.name),file:s};for(const e of r){const r=e.get("key");r.isReferencedIdentifier()?a(r,o):r.traverse(l,o);const s=e.node;if(!r.isConstantExpression()){const e=t.scope.generateUidIdentifierBasedOnNode(s.key);t.scope.push({id:e,kind:"let"}),i.push(n.types.expressionStatement(n.types.assignmentExpression("=",n.types.cloneNode(e),s.key))),s.key=n.types.cloneNode(e)}}return i};var n=r(9),s=r(70);const i=n.traverse.visitors.merge([{Super(e){const{node:t,parentPath:r}=e;r.isCallExpression({callee:t})&&this.push(r)}},s.environmentVisitor]),o={"TSTypeAnnotation|TypeAnnotation"(e){e.skip()},ReferencedIdentifier(e){this.scope.hasOwnBinding(e.node.name)&&(this.scope.rename(e.node.name),e.skip())}};function a(e,t){if(t.classBinding&&t.classBinding===e.scope.getBinding(e.node.name)){const r=t.file.addHelper("classNameTDZError"),s=n.types.callExpression(r,[n.types.stringLiteral(e.node.name)]);e.replaceWith(n.types.sequenceExpression([s,e.node])),e.skip()}}const l={ReferencedIdentifier:a}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.enableFeature=function(e,t,r){let n,s;c(e,t)&&!f(e,t)||(e.set(o,e.get(o)|t),"#__internal__@babel/preset-env__prefer-true-but-false-is-ok-if-it-prevents-an-error"===r?(p(e,t,!0),e.set(l,e.get(l)|t)):"#__internal__@babel/preset-env__prefer-false-but-true-is-ok-if-it-prevents-an-error"===r?(p(e,t,!1),e.set(l,e.get(l)|t)):p(e,t,r));for(const[t,r]of i){if(!c(e,t))continue;const i=u(e,t);if(!f(e,t)){if(n===!i)throw new Error("'loose' mode configuration must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled).");n=i,s=r}}if(void 0!==n)for(const[t,r]of i)c(e,t)&&u(e,t)!==n&&p(e,t,n)},t.isLoose=u,t.verifyUsedFeatures=function(e,t){if((0,n.hasOwnDecorators)(e.node)){if(!c(t,s.decorators))throw e.buildCodeFrameError('Decorators are not enabled.\nIf you are using ["@babel/plugin-proposal-decorators", { "legacy": true }], make sure it comes *before* "@babel/plugin-proposal-class-properties" and enable loose mode, like so:\n\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n\t["@babel/plugin-proposal-class-properties", { "loose": true }]');if(e.isPrivate())throw e.buildCodeFrameError(`Private ${e.isClassMethod()?"methods":"fields"} in decorated classes are not supported yet.`)}if(null!=e.isPrivateMethod&&e.isPrivateMethod()&&!c(t,s.privateMethods))throw e.buildCodeFrameError("Class private methods are not enabled.");if(e.isPrivateName()&&e.parentPath.isBinaryExpression({operator:"in",left:e.node})&&!c(t,s.privateIn))throw e.buildCodeFrameError("Private property in checks are not enabled.");if(e.isProperty()&&!c(t,s.fields))throw e.buildCodeFrameError("Class fields are not enabled.");if(null!=e.isStaticBlock&&e.isStaticBlock()&&!c(t,s.staticBlocks))throw e.buildCodeFrameError("Static class blocks are not enabled. Please add `@babel/plugin-proposal-class-static-block` to your configuration.")},t.FEATURES=void 0;var n=r(311);const s=Object.freeze({fields:2,privateMethods:4,decorators:8,privateIn:16,staticBlocks:32});t.FEATURES=s;const i=new Map([[s.fields,"@babel/plugin-proposal-class-properties"],[s.privateMethods,"@babel/plugin-proposal-private-methods"],[s.privateIn,"@babel/plugin-proposal-private-property-in-object"]]),o="@babel/plugin-class-features/featuresKey",a="@babel/plugin-class-features/looseKey",l="@babel/plugin-class-features/looseLowPriorityKey/#__internal__@babel/preset-env__please-overwrite-loose-instead-of-throwing";function c(e,t){return!!(e.get(o)&t)}function u(e,t){return!!(e.get(a)&t)}function p(e,t,r){r?e.set(a,e.get(a)|t):e.set(a,e.get(a)&~t),e.set(l,e.get(l)&~t)}function f(e,t){return!!(e.get(l)&t)}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-private-property-in-object",manipulateOptions(e,t){t.plugins.push("privateIn")}})));t.default=n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-logical-assignment-operators",manipulateOptions(e,t){t.plugins.push("logicalAssignment")}})));t.default=n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-nullish-coalescing-operator",manipulateOptions(e,t){t.plugins.push("nullishCoalescingOperator")}})));t.default=n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-optional-chaining",manipulateOptions(e,t){t.plugins.push("optionalChaining")}})));t.default=n},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isTransparentExprWrapper=s,t.skipTransparentExprWrappers=function(e){for(;s(e.node);)e=e.get("expression");return e};var n=r(0);function s(e){return n.isTSAsExpression(e)||n.isTSTypeAssertion(e)||n.isTSNonNullExpression(e)||n.isTypeCastExpression(e)||n.isParenthesizedExpression(e)}},(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=(0,r(4).declare)((e=>(e.assertVersion(7),{name:"syntax-export-namespace-from",manipulateOptions(e,t){t.plugins.push("exportNamespaceFrom")}})));t.default=n}],t={};function r(n){var s=t[n];if(void 0!==s)return s.exports;var i=t[n]={id:n,loaded:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.loaded=!0,i.exports}return r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),r(355),r(361)})()})); //# sourceMappingURL=vue3-sfc-loader.js.map ================================================ FILE: frontend/src/main.ts ================================================ import 'crawlab-ui/dist/style.css'; import 'vue'; import {createApp} from 'crawlab-ui'; (async function () { await createApp(); })(); ================================================ FILE: frontend/src/shims-vue.d.ts ================================================ declare module '*.scss'; declare module '*.vue' { import {DefineComponent} from 'vue'; const component: DefineComponent<{}, {}, any>; export default component; } ================================================ FILE: frontend/tsconfig.json ================================================ { "compilerOptions": { "declaration": true, "target": "esnext", "module": "esnext", "strict": true, "jsx": "preserve", "importHelpers": true, "moduleResolution": "node", "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "sourceMap": true, "baseUrl": ".", "paths": { "@/*": [ "src/*" ] }, "lib": [ "esnext", "dom", "dom.iterable", "scripthost" ], "typeRoots": [ "src/interfaces" ] }, "include": [ "src/shims-vue.d.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "__test__/**/*.spec.ts" ], "exclude": [ "node_modules", "src/**/*.js" ] } ================================================ FILE: frontend/vite.config.ts ================================================ import {resolve} from 'path'; import {defineConfig, splitVendorChunkPlugin} from 'vite'; import vue from '@vitejs/plugin-vue'; import dynamicImport from 'vite-plugin-dynamic-import'; import {visualizer} from 'rollup-plugin-visualizer'; import externalGlobals from 'rollup-plugin-external-globals'; import {externalizeDeps} from 'vite-plugin-externalize-deps'; export default defineConfig({ build: { rollupOptions: { output: { manualChunks: (id) => { if (id.includes('node_modules')) { if (id.includes('@fortawesome')) return '@fortawesome'; if (id.includes('element-plus')) return 'element-plus'; if (id.includes('zrender')) return 'zrender'; if (id.includes('echarts')) return 'echarts'; if (id.includes('codemirror')) return 'codemirror'; if (id.includes('atom-material-icons')) return 'atom-material-icons'; if (id.includes('crawlab-ui')) return 'crawlab-ui';; return 'vendor.[hash]'; } } }, external: [ // 'codemirror', // 'echarts', ], plugins: [ // @ts-ignore // externalGlobals({ // // codemirror: 'CodeMirror', // echarts: 'echarts', // }) ], } }, resolve: { dedupe: ['vue', 'element-plus', 'codemirror'], alias: [ {find: '@', replacement: resolve(__dirname, 'src')}, ], extensions: [ '.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.scss', ] }, plugins: [ vue(), dynamicImport(), // splitVendorChunkPlugin(), // externalizeDeps(), // @ts-ignore visualizer({ open: true, // open: false, }), ], server: { cors: true, }, }); ================================================ FILE: frontend/vue.config.js ================================================ const path = require("path") const CopyWebpackPlugin = require('copy-webpack-plugin') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin const alias = { 'crawlab-ui$': 'crawlab-ui/dist/crawlab-ui.umd.min.js', 'element-plus$': 'element-plus/dist/index.full.min.js', 'echarts$': 'echarts/dist/echarts.min.js', 'codemirror$': 'codemirror/lib/codemirror.js', } const optimization = { splitChunks: { chunks: 'initial', minSize: 20000, minChunks: 1, maxAsyncRequests: 3, cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, } const config = { pages: { index: { entry: 'src/main.ts', template: 'public/index.html', filename: 'index.html', title: 'Crawlab | Distributed Web Crawler Platform' } }, outputDir: './dist', configureWebpack: { optimization, resolve: { alias, }, plugins: [] } } if (['development', 'local'].includes(process.env.NODE_ENV)) { // do nothing } else if (['production', 'docker'].includes(process.env.NODE_ENV)) { config.configureWebpack.plugins.push(new CopyWebpackPlugin({ patterns: [ { from: path.resolve(__dirname, 'public/js'), } ] })) } else if (['analyze'].includes(process.env.NODE_ENV)) { config.configureWebpack.plugins.push(new BundleAnalyzerPlugin({ analyzePort: 8890, })) } module.exports = config ================================================ FILE: fs/.editorconfig ================================================ root = true [*.go] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true ================================================ FILE: fs/.github/workflows/test.yml ================================================ name: Test and coverage on: [ push, pull_request ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Go environment uses: actions/setup-go@v2.1.3 with: # The Go version to download (if necessary) and use. Supports semver spec and ranges. go-version: 1.15 # - name: Download Binary Files # run: | # mkdir -p $GITHUB_WORKSPACE/seaweedfs # curl https://github.com/chrislusf/seaweedfs/releases/download/2.48/linux_amd64.tar.gz -o $GITHUB_WORKSPACE/seaweedfs/linux_amd64.tar.gz # cd $GITHUB_WORKSPACE/seaweedfs # ls -l # tar -zxf linux_amd64.tar.gz - name: Download Binary Files uses: fabriciobastian/download-release-asset-action@v1.0.6 with: # A specific release version. Defaults to latest version: 2.48 # default is latest # Relative path to the repository in the format user/repo e.g.: myuser/my-repository repository: chrislusf/seaweedfs # default is # The name of the asset to download from the release file: linux_amd64.tar.gz # Path to the directory where to download the asset out: seaweedfs # optional, default is . - name: Extract Binary Files run: | cd $GITHUB_WORKSPACE/seaweedfs tar -zxf linux_amd64.tar.gz - name: Validate Binary Files run: | cd $GITHUB_WORKSPACE/seaweedfs ls -l weed - name: Run Tests run: go test ./... -race -coverprofile=coverage.txt -covermode=atomic -coverpkg github.com/crawlab-team/crawlab/fs - name: Codecov uses: codecov/codecov-action@v1.5.0 with: # Repository upload token - get it from codecov.io. Required only for private repositories token: ${{ secrets.CODECOV_TOKEN }} # Comma-separated list of files to upload ================================================ FILE: fs/.gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) vendor/ tmp/ .idea/ .DS_Store coverage.txt filerldb2 seaweedfs *.txt ================================================ FILE: fs/Dockerfile ================================================ FROM golang:1.15 WORKDIR /app ADD ./go.mod /app ADD ./go.sum /app RUN go mod download CMD ["sh", "./bin/test.sh"] ================================================ FILE: fs/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2020, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: fs/README.md ================================================ # crawlab-fs [![codecov](https://codecov.io/gh/crawlab-team/crawlab-fs/branch/main/graph/badge.svg?token=KOXJPXWAKI)](https://codecov.io/gh/crawlab-team/crawlab-fs) Backend file system module for Crawlab ================================================ FILE: fs/bin/start.sh ================================================ #!/bin/sh if [ -e ./tmp ]; then : else mkdir ./tmp fi if [ -x /usr/local/bin/weed ]; then weed server \ -dir ./tmp \ -master.dir ./tmp \ -volume.dir.idx ./tmp \ -ip localhost \ -ip.bind 0.0.0.0 \ -filer else ./seaweedfs/weed server \ -dir ./tmp \ -master.dir ./tmp \ -volume.dir.idx ./tmp \ -ip localhost \ -ip.bind 0.0.0.0 \ -filer fi ================================================ FILE: fs/bin/stop.sh ================================================ #!/bin/sh kill -9 `ps axu|grep weed|grep -v grep|awk '{print \$2}'|xargs` ================================================ FILE: fs/constants.go ================================================ package fs import "os" const ( FilerResponseNotFoundErrorMessage = "response status code: 404" FilerStatusNotFoundErrorMessage = "Status:404 Not Found" ) const ( DefaultDirMode = os.FileMode(0766) DefaultFileMode = os.FileMode(0666) ) const ( MethodUpdateFile = "update-file" MethodUploadFile = "upload-file" MethodUploadDir = "upload-dir" ) ================================================ FILE: fs/docker-compose.yml ================================================ version: '2' services: server: image: chrislusf/seaweedfs # use a remote image container_name: seaweedfs-server restart: always # command: "server -dir /data -master.dir /data -volume.dir.idx /data -ip localhost -ip.bind 0.0.0.0 -filer -encryptVolumeData" command: "server -dir /data -master.dir /data -volume.dir.idx /data -ip localhost -ip.bind 0.0.0.0 -filer" ports: - 8888:8888 #volumes: # - /data/seaweedfs:/data ================================================ FILE: fs/errors.go ================================================ package fs import "errors" var ErrorFsNotExists = errors.New("not exists") ================================================ FILE: fs/go.mod ================================================ module github.com/crawlab-team/crawlab/fs go 1.22 replace github.com/crawlab-team/crawlab/trace => ../trace require ( github.com/apex/log v1.9.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/crawlab-team/crawlab/trace v0.0.0-20240614095218-7b4ee8399ab0 github.com/crawlab-team/goseaweedfs v0.6.3 github.com/emirpasic/gods v1.18.1 github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.9.0 ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/ztrue/tracerr v0.4.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: fs/go.sum ================================================ 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 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/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/crawlab-team/goseaweedfs v0.6.3 h1:f96H2QCLrZpof9na1mhIKouKrv8p32XRUyouSVm4YHU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 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/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04= 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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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.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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= ================================================ FILE: fs/interface.go ================================================ package fs import ( "github.com/crawlab-team/goseaweedfs" "time" ) type Manager interface { Init() (err error) Close() (err error) ListDir(remotePath string, isRecursive bool) (files []goseaweedfs.FilerFileInfo, err error) UploadFile(localPath, remotePath string, args ...interface{}) (err error) UploadDir(localPath, remotePath string, args ...interface{}) (err error) DownloadFile(remotePath, localPath string, args ...interface{}) (err error) DownloadDir(remotePath, localPath string, args ...interface{}) (err error) DeleteFile(remotePath string) (err error) DeleteDir(remotePath string) (err error) SyncLocalToRemote(localPath, remotePath string, args ...interface{}) (err error) SyncRemoteToLocal(remotePath, localPath string, args ...interface{}) (err error) GetFile(remotePath string, args ...interface{}) (data []byte, err error) GetFileInfo(remotePath string) (file *goseaweedfs.FilerFileInfo, err error) UpdateFile(remotePath string, data []byte, args ...interface{}) (err error) Exists(remotePath string, args ...interface{}) (ok bool, err error) SetFilerUrl(url string) SetFilerAuthKey(authKey string) SetTimeout(timeout time.Duration) SetWorkerNum(num int) SetRetryInterval(interval time.Duration) SetRetryNum(num int) SetMaxQps(qps int) } ================================================ FILE: fs/lib/copy/copy.go ================================================ package copy import ( "fmt" "io" "io/ioutil" "os" "path/filepath" "syscall" ) func CopyDirectory(scrDir, dest string) error { entries, err := ioutil.ReadDir(scrDir) if err != nil { return err } for _, entry := range entries { sourcePath := filepath.Join(scrDir, entry.Name()) destPath := filepath.Join(dest, entry.Name()) fileInfo, err := os.Stat(sourcePath) if err != nil { return err } stat, ok := fileInfo.Sys().(*syscall.Stat_t) if !ok { return fmt.Errorf("failed to get raw syscall.Stat_t data for '%s'", sourcePath) } switch fileInfo.Mode() & os.ModeType { case os.ModeDir: if err := CreateIfNotExists(destPath, 0755); err != nil { return err } if err := CopyDirectory(sourcePath, destPath); err != nil { return err } case os.ModeSymlink: if err := CopySymLink(sourcePath, destPath); err != nil { return err } default: if err := Copy(sourcePath, destPath); err != nil { return err } } if err := os.Lchown(destPath, int(stat.Uid), int(stat.Gid)); err != nil { return err } isSymlink := entry.Mode()&os.ModeSymlink != 0 if !isSymlink { if err := os.Chmod(destPath, entry.Mode()); err != nil { return err } } } return nil } func Copy(srcFile, dstFile string) error { out, err := os.Create(dstFile) if err != nil { return err } defer out.Close() in, err := os.Open(srcFile) defer in.Close() if err != nil { return err } _, err = io.Copy(out, in) if err != nil { return err } return nil } func Exists(filePath string) bool { if _, err := os.Stat(filePath); os.IsNotExist(err) { return false } return true } func CreateIfNotExists(dir string, perm os.FileMode) error { if Exists(dir) { return nil } if err := os.MkdirAll(dir, perm); err != nil { return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error()) } return nil } func CopySymLink(source, dest string) error { link, err := os.Readlink(source) if err != nil { return err } return os.Symlink(link, dest) } ================================================ FILE: fs/options.go ================================================ package fs import "time" type Option func(m Manager) func WithFilerUrl(url string) Option { return func(m Manager) { m.SetFilerUrl(url) } } func WithFilerAuthKey(authKey string) Option { return func(m Manager) { m.SetFilerAuthKey(authKey) } } func WithTimeout(timeout time.Duration) Option { return func(m Manager) { m.SetTimeout(timeout) } } func WithWorkerNum(num int) Option { return func(m Manager) { m.SetWorkerNum(num) } } func WithRetryInterval(interval time.Duration) Option { return func(m Manager) { m.SetRetryInterval(interval) } } func WithRetryNum(num int) Option { return func(m Manager) { m.SetRetryNum(num) } } func WithMaxQps(qps int) Option { return func(m Manager) { m.SetMaxQps(qps) } } ================================================ FILE: fs/seaweedfs_manager.go ================================================ package fs import ( "bytes" "errors" "fmt" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/trace" "github.com/crawlab-team/goseaweedfs" "github.com/emirpasic/gods/queues/linkedlistqueue" "github.com/google/uuid" "io" "io/ioutil" "net/http" "net/url" "os" "path" "path/filepath" "strings" "time" ) type seaweedFsManagerFn func(params seaweedFsManagerParams) (res seaweedFsManagerResults) type seaweedFsManagerHandle struct { params seaweedFsManagerParams fn seaweedFsManagerFn resChan chan seaweedFsManagerResults } type seaweedFsManagerParams struct { localPath string remotePath string isRecursive bool collection string ttl string urlValues url.Values data []byte } type seaweedFsManagerResults struct { files []goseaweedfs.FilerFileInfo file *goseaweedfs.FilerFileInfo data []byte ok bool err error } type SeaweedFsManager struct { // settings variables filerUrl string timeout time.Duration authKey string workerNum int retryNum uint64 retryInterval time.Duration maxQps int // internals f *goseaweedfs.Filer q *linkedlistqueue.Queue cr int ch chan seaweedFsManagerHandle closed bool } func (m *SeaweedFsManager) Init() (err error) { // filer options var filerOpts []goseaweedfs.FilerOption // auth key if m.authKey != "" { filerOpts = append(filerOpts, goseaweedfs.WithFilerAuthKey(m.authKey)) } // handle channel m.ch = make(chan seaweedFsManagerHandle, m.workerNum) // filer instance m.f, err = goseaweedfs.NewFiler(m.filerUrl, &http.Client{Timeout: m.timeout}, filerOpts...) if err != nil { return trace.TraceError(err) } // start async go m.start() return nil } func (m *SeaweedFsManager) Close() (err error) { m.closed = true if err := m.f.Close(); err != nil { return trace.TraceError(err) } return nil } func (m *SeaweedFsManager) ListDir(remotePath string, isRecursive bool) (files []goseaweedfs.FilerFileInfo, err error) { params := seaweedFsManagerParams{ remotePath: remotePath, isRecursive: isRecursive, } res := m.process(params, m.listDir) return res.files, res.err } func (m *SeaweedFsManager) ListDirRecursive(remotePath string) (files []goseaweedfs.FilerFileInfo, err error) { params := seaweedFsManagerParams{ remotePath: remotePath, } res := m.process(params, m.listDirRecursive) return res.files, res.err } func (m *SeaweedFsManager) UploadFile(localPath, remotePath string, args ...interface{}) (err error) { localPath, err = filepath.Abs(localPath) if err != nil { return trace.TraceError(err) } collection, ttl := getCollectionAndTtlFromArgs(args...) params := seaweedFsManagerParams{ localPath: localPath, remotePath: remotePath, collection: collection, ttl: ttl, } res := m.process(params, m.uploadFile) return res.err } func (m *SeaweedFsManager) UploadDir(localPath, remotePath string, args ...interface{}) (err error) { localPath, err = filepath.Abs(localPath) if err != nil { return trace.TraceError(err) } collection, ttl := getCollectionAndTtlFromArgs(args...) params := seaweedFsManagerParams{ localPath: localPath, remotePath: remotePath, collection: collection, ttl: ttl, } res := m.process(params, m.uploadDir) return res.err } func (m *SeaweedFsManager) DownloadFile(remotePath, localPath string, args ...interface{}) (err error) { localPath, err = filepath.Abs(localPath) if err != nil { return trace.TraceError(err) } collection, ttl := getCollectionAndTtlFromArgs(args...) urlValues := getUrlValuesFromArgs(args...) params := seaweedFsManagerParams{ localPath: localPath, remotePath: remotePath, collection: collection, ttl: ttl, urlValues: urlValues, } res := m.process(params, m.downloadFile) return res.err } func (m *SeaweedFsManager) DownloadDir(remotePath, localPath string, args ...interface{}) (err error) { localPath, err = filepath.Abs(localPath) if err != nil { return trace.TraceError(err) } params := seaweedFsManagerParams{ remotePath: remotePath, } res := m.process(params, m.downloadDir) return res.err } func (m *SeaweedFsManager) DeleteFile(remotePath string) (err error) { params := seaweedFsManagerParams{ remotePath: remotePath, } res := m.process(params, m.deleteFile) return res.err } func (m *SeaweedFsManager) DeleteDir(remotePath string) (err error) { params := seaweedFsManagerParams{ remotePath: remotePath, } res := m.process(params, m.deleteDir) return res.err } func (m *SeaweedFsManager) SyncLocalToRemote(localPath, remotePath string, args ...interface{}) (err error) { localPath, err = filepath.Abs(localPath) if err != nil { return trace.TraceError(err) } collection, ttl := getCollectionAndTtlFromArgs(args...) params := seaweedFsManagerParams{ localPath: localPath, remotePath: remotePath, collection: collection, ttl: ttl, } res := m.process(params, m.syncLocalToRemote) return res.err } func (m *SeaweedFsManager) SyncRemoteToLocal(remotePath, localPath string, args ...interface{}) (err error) { collection, ttl := getCollectionAndTtlFromArgs(args...) params := seaweedFsManagerParams{ localPath: localPath, remotePath: remotePath, collection: collection, ttl: ttl, } res := m.process(params, m.syncRemoteToLocal) return res.err } func (m *SeaweedFsManager) GetFile(remotePath string, args ...interface{}) (data []byte, err error) { urlValues := getUrlValuesFromArgs(args...) params := seaweedFsManagerParams{ remotePath: remotePath, urlValues: urlValues, } res := m.process(params, m.getFile) return res.data, res.err } func (m *SeaweedFsManager) GetFileInfo(remotePath string) (file *goseaweedfs.FilerFileInfo, err error) { params := seaweedFsManagerParams{ remotePath: remotePath, } res := m.process(params, m.getFileInfo) return res.file, res.err } func (m *SeaweedFsManager) UpdateFile(remotePath string, data []byte, args ...interface{}) (err error) { collection, ttl := getCollectionAndTtlFromArgs(args...) params := seaweedFsManagerParams{ remotePath: remotePath, collection: collection, ttl: ttl, data: data, } res := m.process(params, m.updateFile) return res.err } func (m *SeaweedFsManager) Exists(remotePath string, args ...interface{}) (ok bool, err error) { _, err = m.GetFile(remotePath, args...) if err == nil { // exists return true, nil } if strings.Contains(err.Error(), FilerStatusNotFoundErrorMessage) { // not exists return false, nil } return ok, trace.TraceError(err) } func (m *SeaweedFsManager) SetFilerUrl(url string) { m.filerUrl = url } func (m *SeaweedFsManager) SetFilerAuthKey(authKey string) { m.authKey = authKey } func (m *SeaweedFsManager) SetTimeout(timeout time.Duration) { m.timeout = timeout } func (m *SeaweedFsManager) SetWorkerNum(num int) { m.workerNum = num } func (m *SeaweedFsManager) SetRetryInterval(interval time.Duration) { m.retryInterval = interval } func (m *SeaweedFsManager) SetRetryNum(num int) { m.retryNum = uint64(num) } func (m *SeaweedFsManager) SetMaxQps(qps int) { m.maxQps = qps } func (m *SeaweedFsManager) newHandle(params seaweedFsManagerParams, fn seaweedFsManagerFn) (handle seaweedFsManagerHandle) { return seaweedFsManagerHandle{ params: params, fn: fn, resChan: make(chan seaweedFsManagerResults), } } func (m *SeaweedFsManager) start() { for { if m.closed { return } handle := <-m.ch go func() { if err := backoff.Retry(func() error { res := handle.fn(handle.params) if res.err != nil { return res.err } handle.resChan <- res return nil }, backoff.WithMaxRetries( backoff.NewConstantBackOff(m.retryInterval), m.retryNum), ); err != nil { handle.resChan <- m.error(err) } m.wait() }() } } func (m *SeaweedFsManager) process(params seaweedFsManagerParams, fn seaweedFsManagerFn) (res seaweedFsManagerResults) { handle := m.newHandle(params, fn) //log.Infof("handle: %v", handle) m.ch <- handle res = <-handle.resChan return } func (m *SeaweedFsManager) error(err error) (res seaweedFsManagerResults) { if err != nil { trace.PrintError(err) } return seaweedFsManagerResults{err: err} } func (m *SeaweedFsManager) wait() { ms := float32(1) / float32(m.maxQps) * 1e3 d := time.Duration(ms) * time.Millisecond time.Sleep(d) } func (m *SeaweedFsManager) getCollectionAndTtlArgsFromParams(params seaweedFsManagerParams) (args []interface{}) { if params.collection != "" { args = append(args, params.collection) } if params.ttl != "" { args = append(args, params.ttl) } return args } func (m *SeaweedFsManager) listDir(params seaweedFsManagerParams) (res seaweedFsManagerResults) { var err error if params.isRecursive { res.files, err = m.ListDirRecursive(params.remotePath) } else { res.files, err = m.f.ListDir(params.remotePath) } if err != nil { return m.error(err) } return } func (m *SeaweedFsManager) listDirRecursive(params seaweedFsManagerParams) (res seaweedFsManagerResults) { entries, err := m.f.ListDir(params.remotePath) if err != nil { return m.error(err) } for _, file := range entries { file = goseaweedfs.GetFileWithExtendedFields(file) if file.IsDir { file.Children, err = m.ListDirRecursive(file.FullPath) if err != nil { return m.error(err) } } res.files = append(res.files, file) } return } func (m *SeaweedFsManager) uploadFile(params seaweedFsManagerParams) (res seaweedFsManagerResults) { r, err := m.f.UploadFile(params.localPath, params.remotePath, params.collection, params.ttl) if err != nil { return m.error(err) } if r.Error != "" { err = errors.New(r.Error) return m.error(err) } return } func (m *SeaweedFsManager) uploadDir(params seaweedFsManagerParams) (res seaweedFsManagerResults) { args := m.getCollectionAndTtlArgsFromParams(params) if strings.HasSuffix(params.localPath, "/") { params.localPath = params.localPath[:(len(params.localPath) - 1)] } if !strings.HasPrefix(params.remotePath, "/") { params.remotePath = "/" + params.remotePath } files, err := goseaweedfs.ListFilesRecursive(params.localPath) if err != nil { return m.error(err) } for _, info := range files { newFilePath := params.remotePath + strings.Replace(info.Path, params.localPath, "", -1) if err := m.UploadFile(info.Path, newFilePath, args...); err != nil { return m.error(err) } } return } func (m *SeaweedFsManager) downloadFile(params seaweedFsManagerParams) (res seaweedFsManagerResults) { err := m.f.Download(params.remotePath, params.urlValues, func(reader io.Reader) error { data, err := ioutil.ReadAll(reader) if err != nil { return trace.TraceError(err) } dirPath := filepath.Dir(params.localPath) _, err = os.Stat(dirPath) if err != nil { // if not exists, create a new directory if err := os.MkdirAll(dirPath, DefaultDirMode); err != nil { return trace.TraceError(err) } } fileMode := DefaultFileMode fileInfo, err := os.Stat(params.localPath) if err == nil { // if file already exists, save file mode and remove it fileMode = fileInfo.Mode() if err := os.Remove(params.localPath); err != nil { return trace.TraceError(err) } } if err := ioutil.WriteFile(params.localPath, data, fileMode); err != nil { return trace.TraceError(err) } return nil }) if err != nil { return m.error(err) } return } func (m *SeaweedFsManager) downloadDir(params seaweedFsManagerParams) (res seaweedFsManagerResults) { args := m.getCollectionAndTtlArgsFromParams(params) var files []goseaweedfs.FilerFileInfo files, res.err = m.ListDir(params.remotePath, true) for _, file := range files { if file.IsDir { if err := m.DownloadDir(file.FullPath, path.Join(params.localPath, file.Name), args...); err != nil { return m.error(err) } } else { if err := m.DownloadFile(file.FullPath, path.Join(params.localPath, file.Name), args...); err != nil { return m.error(err) } } } return } func (m *SeaweedFsManager) deleteFile(params seaweedFsManagerParams) (res seaweedFsManagerResults) { if err := m.f.DeleteFile(params.remotePath); err != nil { return m.error(err) } return } func (m *SeaweedFsManager) deleteDir(params seaweedFsManagerParams) (res seaweedFsManagerResults) { if err := m.f.DeleteDir(params.remotePath); err != nil { return m.error(err) } return } func (m *SeaweedFsManager) syncLocalToRemote(params seaweedFsManagerParams) (res seaweedFsManagerResults) { // args args := m.getCollectionAndTtlArgsFromParams(params) // raise error if local path does not exist if _, err := os.Stat(params.localPath); err != nil { return m.error(err) } // get files and maps localFiles, remoteFiles, localFilesMap, remoteFilesMap, err := getFilesAndFilesMaps(m.f, params.localPath, params.remotePath) if err != nil { return m.error(err) } // compare remote files with local files and delete files absent in local files for _, remoteFile := range remoteFiles { // attempt to get corresponding local file _, ok := localFilesMap[remoteFile.FullPath] if !ok { // file does not exist on local, delete if remoteFile.IsDir { if err := m.DeleteDir(remoteFile.FullPath); err != nil { return m.error(err) } } else { if err := m.DeleteFile(remoteFile.FullPath); err != nil { return m.error(err) } } } } // compare local files with remote files and upload files with difference for _, localFile := range localFiles { // skip .git if IsGitFile(localFile) { continue } // corresponding remote file path fileRemotePath := fmt.Sprintf("%s%s", params.remotePath, strings.Replace(localFile.Path, params.localPath, "", -1)) // attempt to get corresponding remote file remoteFile, ok := remoteFilesMap[fileRemotePath] if !ok { // file does not exist on remote, upload if err := m.UploadFile(localFile.Path, fileRemotePath, args...); err != nil { return m.error(err) } } else { // file exists on remote, upload if md5sum values are different if remoteFile.Md5 != localFile.Md5 { if err := m.UploadFile(localFile.Path, fileRemotePath, args...); err != nil { return m.error(err) } } } } return } func (m *SeaweedFsManager) syncRemoteToLocal(params seaweedFsManagerParams) (res seaweedFsManagerResults) { // args args := m.getCollectionAndTtlArgsFromParams(params) // create directory if local path does not exist if _, err := os.Stat(params.localPath); err != nil { if err := os.MkdirAll(params.localPath, os.ModePerm); err != nil { return m.error(err) } } // get files and maps localFiles, remoteFiles, localFilesMap, remoteFilesMap, err := getFilesAndFilesMaps(m.f, params.localPath, params.remotePath) if err != nil { return m.error(err) } // compare local files with remote files and delete files absent on remote for _, localFile := range localFiles { // skip .git if IsGitFile(localFile) { continue } // corresponding remote file path fileRemotePath := fmt.Sprintf("%s%s", params.remotePath, strings.Replace(localFile.Path, params.localPath, "", -1)) // attempt to get corresponding remote file _, ok := remoteFilesMap[fileRemotePath] if !ok { // file does not exist on remote, upload if err := os.Remove(localFile.Path); err != nil { return m.error(err) } } } // compare remote files with local files and download if files with difference for _, remoteFile := range remoteFiles { // directory if remoteFile.IsDir { localDirRelativePath := strings.Replace(remoteFile.FullPath, params.remotePath, "", 1) localDirPath := fmt.Sprintf("%s%s", params.localPath, localDirRelativePath) if err := m.SyncRemoteToLocal(remoteFile.FullPath, localDirPath); err != nil { return m.error(err) } continue } // local file path localFileRelativePath := strings.Replace(remoteFile.FullPath, params.remotePath, "", 1) localFilePath := fmt.Sprintf("%s%s", params.localPath, localFileRelativePath) // attempt to get corresponding local file localFile, ok := localFilesMap[remoteFile.FullPath] if !ok { // file does not exist on local, download if err := m.DownloadFile(remoteFile.FullPath, localFilePath); err != nil { return m.error(err) } } else { // file exists on remote, download if md5sum values are different if remoteFile.Md5 != localFile.Md5 { if err := m.DownloadFile(remoteFile.FullPath, localFilePath, args...); err != nil { return m.error(err) } } } } return } func (m *SeaweedFsManager) getFile(params seaweedFsManagerParams) (res seaweedFsManagerResults) { var buf bytes.Buffer res.err = m.f.Download(params.remotePath, params.urlValues, func(reader io.Reader) error { _, err := io.Copy(&buf, reader) if err != nil { return trace.TraceError(err) } return nil }) res.data = buf.Bytes() return } func (m *SeaweedFsManager) getFileInfo(params seaweedFsManagerParams) (res seaweedFsManagerResults) { arr := strings.Split(params.remotePath, "/") dirName := strings.Join(arr[:(len(arr)-1)], "/") files, err := m.f.ListDir(dirName) if err != nil { return m.error(err) } for _, f := range files { if f.FullPath == params.remotePath { res.file = &f return } } return m.error(ErrorFsNotExists) } func (m *SeaweedFsManager) updateFile(params seaweedFsManagerParams) (res seaweedFsManagerResults) { tmpRootDir := os.TempDir() tmpDirPath := path.Join(tmpRootDir, ".seaweedfs") if _, err := os.Stat(tmpDirPath); err != nil { if err := os.MkdirAll(tmpDirPath, os.ModePerm); err != nil { return m.error(err) } } tmpFilePath := path.Join(tmpDirPath, fmt.Sprintf(".%s", uuid.New().String())) if _, err := os.Stat(tmpFilePath); err == nil { if err := os.Remove(tmpFilePath); err != nil { return m.error(err) } } if err := ioutil.WriteFile(tmpFilePath, params.data, os.ModePerm); err != nil { return m.error(err) } params2 := seaweedFsManagerParams{ localPath: tmpFilePath, remotePath: params.remotePath, collection: params.collection, ttl: params.ttl, } if res := m.uploadFile(params2); res.err != nil { return m.error(res.err) } if err := os.Remove(tmpFilePath); err != nil { return m.error(err) } return } func NewSeaweedFsManager(opts ...Option) (m2 Manager, err error) { // manager m := &SeaweedFsManager{ filerUrl: "http://localhost:8888", timeout: 5 * time.Minute, workerNum: 1, retryInterval: 500 * time.Millisecond, retryNum: 3, maxQps: 5, q: linkedlistqueue.New(), } // apply options for _, opt := range opts { opt(m) } // initialize if err := m.Init(); err != nil { return nil, err } return m, nil } var _seaweedFsManager Manager func GetSeaweedFsManager(opts ...Option) (m2 Manager, err error) { if _seaweedFsManager == nil { _seaweedFsManager, err = NewSeaweedFsManager(opts...) if err != nil { return nil, err } } return _seaweedFsManager, nil } ================================================ FILE: fs/test/base.go ================================================ package test import ( fs "github.com/crawlab-team/crawlab/fs" "os" "testing" "time" ) func init() { var err error T, err = NewTest() if err != nil { panic(err) } } var T *Test type Test struct { m fs.Manager } func (t *Test) Setup(t2 *testing.T) { t.Cleanup() t2.Cleanup(t.Cleanup) } func (t *Test) Cleanup() { _ = T.m.DeleteDir("/test") // wait to avoid caching time.Sleep(200 * time.Millisecond) } func NewTest() (res *Test, err error) { // test t := &Test{} // filer url filerUrl := os.Getenv("CRAWLAB_FILER_URL") if filerUrl == "" { filerUrl = "http://localhost:8888" } // manager t.m, err = fs.NewSeaweedFsManager( fs.WithFilerUrl(filerUrl), fs.WithTimeout(10*time.Second), ) if err != nil { return nil, err } return t, nil } ================================================ FILE: fs/test/bindata.go ================================================ // Code generated for package test by go-bindata DO NOT EDIT. (@generated) // sources: // bin/start.sh // bin/stop.sh package test import ( "bytes" "compress/gzip" "fmt" "io" "io/ioutil" "os" "path/filepath" "strings" "time" ) func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } var buf bytes.Buffer _, err = io.Copy(&buf, gz) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } if clErr != nil { return nil, err } return buf.Bytes(), nil } type asset struct { bytes []byte info os.FileInfo } type bindataFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } // Name return file name func (fi bindataFileInfo) Name() string { return fi.name } // Size return file size func (fi bindataFileInfo) Size() int64 { return fi.size } // Mode return file mode func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } // Mode return file modify time func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } // IsDir return file whether a directory func (fi bindataFileInfo) IsDir() bool { return fi.mode&os.ModeDir != 0 } // Sys return file is sys mode func (fi bindataFileInfo) Sys() interface{} { return nil } var _binStartSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x8f\x4b\x0e\xc2\x30\x0c\x44\xf7\x3e\xc5\x20\xd6\x4d\x58\xc3\x51\x80\x45\x4b\x1c\xd5\x22\x69\xab\x38\x2d\x3d\x3e\x6a\xa0\x7c\xc4\x05\x90\x57\x7e\xa3\x19\x8f\xb7\x1b\xdb\x48\x67\xb5\x25\xf1\x38\xa2\x62\x18\x9b\xe3\x80\xf3\x01\xb9\xe5\x8e\x80\x3d\x71\x50\x26\x20\x5e\x9d\xa4\x87\x4c\x5e\xe8\x69\x98\x61\x47\x4d\x36\xf4\x97\x3a\x94\xa8\x1b\xb3\xfb\xb0\x97\x55\x39\x4d\x9c\x70\x22\x00\xa8\x5e\x31\x2b\x88\xb5\x66\x4e\xe6\x87\x4f\x7d\x18\x23\x2f\xdc\x88\x9b\xbf\x35\x19\x50\x6e\xb6\xbd\xe6\x37\x33\x8d\x74\x0e\x3b\x53\x66\xc5\x5e\x02\xa7\xf5\x0b\x63\x95\xeb\xa5\x94\x57\xfb\x37\xdd\xbc\xd0\x3d\x00\x00\xff\xff\x09\xef\x85\x28\x89\x01\x00\x00") func binStartShBytes() ([]byte, error) { return bindataRead( _binStartSh, "bin/start.sh", ) } func binStartSh() (*asset, error) { bytes, err := binStartShBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "bin/start.sh", size: 393, mode: os.FileMode(493), modTime: time.Unix(1621153670, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _binStopSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x52\x56\xd4\x4f\xca\xcc\xd3\x2f\xce\xe0\xe2\xca\xce\xcc\xc9\x51\xd0\xb5\x54\x48\x28\x28\x56\x48\xac\x28\xad\x49\x2f\x4a\x2d\x50\x28\x4f\x4d\x4d\x81\xb0\x74\xcb\x14\x40\x74\x4d\x62\x79\xb6\x82\x7a\x75\x41\x51\x66\x5e\x89\x42\x8c\x8a\x51\xad\x7a\x4d\x45\x62\x51\x7a\x71\x02\x20\x00\x00\xff\xff\x6b\x5f\x02\x48\x4a\x00\x00\x00") func binStopShBytes() ([]byte, error) { return bindataRead( _binStopSh, "bin/stop.sh", ) } func binStopSh() (*asset, error) { bytes, err := binStopShBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "bin/stop.sh", size: 74, mode: os.FileMode(493), modTime: time.Unix(1621154552, 0)} a := &asset{bytes: bytes, info: info} return a, nil } // Asset loads and returns the asset for the given name. // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { cannonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[cannonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) } return a.bytes, nil } return nil, fmt.Errorf("Asset %s not found", name) } // MustAsset is like Asset but panics when Asset would return an error. // It simplifies safe initialization of global variables. func MustAsset(name string) []byte { a, err := Asset(name) if err != nil { panic("asset: Asset(" + name + "): " + err.Error()) } return a } // AssetInfo loads and returns the asset info for the given name. // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { cannonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[cannonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) } return a.info, nil } return nil, fmt.Errorf("AssetInfo %s not found", name) } // AssetNames returns the names of the assets. func AssetNames() []string { names := make([]string, 0, len(_bindata)) for name := range _bindata { names = append(names, name) } return names } // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "bin/start.sh": binStartSh, "bin/stop.sh": binStopSh, } // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: // data/ // foo.txt // img/ // a.png // b.png // then AssetDir("data") would return []string{"foo.txt", "img"} // AssetDir("data/img") would return []string{"a.png", "b.png"} // AssetDir("foo.txt") and AssetDir("notexist") would return an error // AssetDir("") will return []string{"data"}. func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { cannonicalName := strings.Replace(name, "\\", "/", -1) pathList := strings.Split(cannonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { return nil, fmt.Errorf("Asset %s not found", name) } } } if node.Func != nil { return nil, fmt.Errorf("Asset %s not found", name) } rv := make([]string, 0, len(node.Children)) for childName := range node.Children { rv = append(rv, childName) } return rv, nil } type bintree struct { Func func() (*asset, error) Children map[string]*bintree } var _bintree = &bintree{nil, map[string]*bintree{ "bin": &bintree{nil, map[string]*bintree{ "start.sh": &bintree{binStartSh, map[string]*bintree{}}, "stop.sh": &bintree{binStopSh, map[string]*bintree{}}, }}, }} // RestoreAsset restores an asset under the given directory func RestoreAsset(dir, name string) error { data, err := Asset(name) if err != nil { return err } info, err := AssetInfo(name) if err != nil { return err } err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) if err != nil { return err } err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) if err != nil { return err } err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) if err != nil { return err } return nil } // RestoreAssets restores an asset under the given directory recursively func RestoreAssets(dir, name string) error { children, err := AssetDir(name) // File if err != nil { return RestoreAsset(dir, name) } // Dir for _, child := range children { err = RestoreAssets(dir, filepath.Join(name, child)) if err != nil { return err } } return nil } func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } ================================================ FILE: fs/test/main_test.go ================================================ package test import ( "testing" ) func TestMain(m *testing.M) { // before test //if err := StartTestSeaweedFs(); err != nil { // panic(err) //} // test m.Run() // close _ = T.m.Close() // after test //_ = StopTestSeaweedFs() } ================================================ FILE: fs/test/seaweedfs_test.go ================================================ package test import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab/fs" "github.com/crawlab-team/crawlab/fs/lib/copy" "github.com/stretchr/testify/require" "io/ioutil" "os" "strings" "sync" "testing" "time" ) func TestNewSeaweedFsManager(t *testing.T) { _, err := fs.NewSeaweedFsManager() require.Nil(t, err) } func TestSeaweedFsManager_ListDir(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data/nested", "/test/data/nested") require.Nil(t, err) valid := false files, err := T.m.ListDir("/test/data", true) require.Nil(t, err) for _, f1 := range files { if f1.Name == "nested" && f1.Children != nil { for _, f2 := range f1.Children { if f2.Name == "nested_test_data.txt" { valid = true } } } } require.True(t, valid) } func TestSeaweedFsManager_UploadFile(t *testing.T) { var err error T.Setup(t) err = T.m.UploadFile("./data/test_data.txt", "/test/data/test_data.txt") require.Nil(t, err) files, err := T.m.ListDir("/test/data", true) require.Nil(t, err) valid := false for _, file := range files { if file.Name == "test_data.txt" { valid = true } } require.True(t, valid) } func TestSeaweedFsManager_UploadDir(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data/nested", "/test/data/nested") require.Nil(t, err) valid := false files, err := T.m.ListDir("/test/data", true) require.Nil(t, err) for _, f1 := range files { if f1.Name == "nested" && f1.Children != nil { for _, f2 := range f1.Children { if f2.Name == "nested_test_data.txt" { valid = true } } } } require.True(t, valid) } func TestSeaweedFsManager_GetFile(t *testing.T) { var err error T.Setup(t) err = T.m.UploadFile("./data/test_data.txt", "/test/data/test_data.txt") require.Nil(t, err) data, err := T.m.GetFile("/test/data/test_data.txt") require.Equal(t, "this is a test data", string(data)) } func TestSeaweedFsManager_DownloadFile(t *testing.T) { var err error T.Setup(t) err = T.m.UploadFile("./data/test_data.txt", "/test/data/test_data.txt") require.Nil(t, err) err = T.m.DownloadFile("/test/data/test_data.txt", "./tmp/test_data.txt") require.Nil(t, err) data, err := ioutil.ReadFile("./tmp/test_data.txt") require.Nil(t, err) require.NotEmpty(t, data) } func TestSeaweedFsManager_DownloadDir(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data/nested", "/test/data/nested") require.Nil(t, err) err = T.m.DownloadDir("/test/data", "./tmp/data") require.Nil(t, err) data, err := ioutil.ReadFile("./data/nested/nested_test_data.txt") require.Nil(t, err) require.NotEmpty(t, data) } func TestSeaweedFsManager_DeleteFile(t *testing.T) { var err error T.Setup(t) err = T.m.UploadFile("./data/test_data.txt", "/test/data/test_data.txt") require.Nil(t, err) err = T.m.DeleteFile("/test/data/test_data.txt") require.Nil(t, err) files, err := T.m.ListDir("/test/data", true) require.Nil(t, err) require.Equal(t, 0, len(files)) } func TestSeaweedFsManager_DeleteDir(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data", "/test/data") require.Nil(t, err) err = T.m.DeleteDir("/test/data/nested") require.Nil(t, err) files, err := T.m.ListDir("/test/data", true) require.Nil(t, err) valid := true for _, file := range files { if file.Name == "nested" && file.IsDir { valid = false } } require.True(t, valid) } func TestSeaweedFsManager_SyncLocalToRemote(t *testing.T) { var err error T.Setup(t) err = copy.CopyDirectory("./data", "./tmp/data") require.Nil(t, err) err = T.m.SyncLocalToRemote("./tmp/data", "/test/data") require.Nil(t, err) data, err := T.m.GetFile("/test/data/test_data.txt") require.Nil(t, err) require.Equal(t, "this is a test data", string(data)) data, err = T.m.GetFile("/test/data/nested/nested_test_data.txt") require.Nil(t, err) require.Equal(t, "this is nested test data", string(data)) err = ioutil.WriteFile("./tmp/data/test_data.txt", []byte("this is changed data"), os.ModePerm) require.Nil(t, err) err = T.m.SyncLocalToRemote("./tmp/data", "/test/data") require.Nil(t, err) data, err = T.m.GetFile("/test/data/test_data.txt") require.Equal(t, "this is changed data", string(data)) err = os.Remove("./tmp/data/test_data.txt") require.Nil(t, err) err = T.m.SyncLocalToRemote("./tmp/data", "/test/data") require.Nil(t, err) valid := true files, err := T.m.ListDir("/test/data", true) for _, file := range files { if file.Name == "test_data.txt" { valid = false } } require.True(t, valid) // check if directory is deleted after sync err = ioutil.WriteFile("./tmp/test.txt", []byte("test"), os.ModePerm) require.Nil(t, err) err = T.m.UploadFile("./tmp/test.txt", "/test/data/folder1/test.txt") require.Nil(t, err) time.Sleep(1 * time.Second) err = T.m.SyncLocalToRemote("./tmp/data", "/test/data") require.Nil(t, err) valid = true files, err = T.m.ListDir("/test/data", true) for _, file := range files { if strings.Contains(file.FullPath, "folder1") { valid = false } } require.True(t, valid) } func TestSeaweedFsManager_SyncRemoteToLocal(t *testing.T) { var err error T.Setup(t) if _, err := os.Stat("./tmp/data"); err == nil { err = os.RemoveAll("./tmp/data") require.Nil(t, err) } err = T.m.UploadDir("./data", "/test/data") require.Nil(t, err) err = T.m.SyncRemoteToLocal("/test/data", "./tmp/data") require.Nil(t, err) data, err := ioutil.ReadFile("./tmp/data/test_data.txt") require.Nil(t, err) require.Equal(t, "this is a test data", string(data)) data, err = ioutil.ReadFile("./tmp/data/nested/nested_test_data.txt") require.Nil(t, err) require.Equal(t, "this is nested test data", string(data)) err = T.m.UpdateFile("/test/data/test_data.txt", []byte("this is changed data")) require.Nil(t, err) err = T.m.SyncRemoteToLocal("/test/data", "./tmp/data") require.Nil(t, err) data, err = ioutil.ReadFile("./tmp/data/test_data.txt") require.Equal(t, "this is changed data", string(data)) err = T.m.DeleteFile("/test/data/test_data.txt") require.Nil(t, err) err = T.m.SyncRemoteToLocal("/test/data", "./tmp/data") require.Nil(t, err) _, err = os.Stat("./tmp/data/test_data.txt") require.NotNil(t, err) } func TestSeaweedFsManager_UpdateFile(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data", "/test/data") require.Nil(t, err) err = T.m.UpdateFile("/test/data/test_data.txt", []byte("this is changed data")) require.Nil(t, err) data, err := T.m.GetFile("/test/data/test_data.txt") require.Nil(t, err) require.Equal(t, "this is changed data", string(data)) } func TestSeaweedFsManager_Exists(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data", "/test/data") require.Nil(t, err) ok, err := T.m.Exists("/test/data/test_data.txt") require.Nil(t, err) require.True(t, ok) ok, err = T.m.Exists("/test/data/test_data_404.txt") require.Nil(t, err) require.False(t, ok) } func TestSeaweedFsManager_ListDirPressure(t *testing.T) { var err error T.Setup(t) err = T.m.UploadDir("./data/nested", "/test/data/nested") require.Nil(t, err) n := int(1e3) doneNum := 0 errNum := 0 startTs := time.Now() wg := sync.WaitGroup{} wg.Add(n) for i := 0; i < n; i++ { go func(i int) { _, err := T.m.ListDir("test/data", true) wg.Done() if err != nil { errNum++ } doneNum++ log.Infof("list dir: %d/%d", doneNum, n) require.Nil(t, err) }(i) } wg.Wait() endTs := time.Now() duration := endTs.Sub(startTs).Milliseconds() fmt.Println(fmt.Sprintf("total: %d", n)) fmt.Println(fmt.Sprintf("errors: %d", errNum)) fmt.Println(fmt.Sprintf("error rate: %.3f", float32(errNum)/float32(n))) fmt.Println(fmt.Sprintf("duration: %dms", duration)) } func TestSeaweedFsManager_UploadFilePressure(t *testing.T) { var err error T.Setup(t) n := int(1e3) doneNum := 0 errNum := 0 startTs := time.Now() wg := sync.WaitGroup{} wg.Add(n) for i := 0; i < n; i++ { go func(i int) { err = T.m.UploadFile("./data/test_data.txt", fmt.Sprintf("/test/data/test_data_%d.txt", i)) wg.Done() if err != nil { errNum++ } doneNum++ log.Infof("upload file: %d/%d", doneNum, n) require.Nil(t, err) }(i) } wg.Wait() endTs := time.Now() duration := endTs.Sub(startTs).Milliseconds() fmt.Println(fmt.Sprintf("total: %d", n)) fmt.Println(fmt.Sprintf("errors: %d", errNum)) fmt.Println(fmt.Sprintf("error rate: %.3f", float32(errNum)/float32(n))) fmt.Println(fmt.Sprintf("duration: %dms", duration)) } func TestSeaweedFsManager_UploadDirPressure(t *testing.T) { var err error T.Setup(t) n := int(1e3) doneNum := 0 errNum := 0 startTs := time.Now() wg := sync.WaitGroup{} wg.Add(n) for i := 0; i < n; i++ { go func(i int) { err = T.m.UploadDir("./data/nested", "/test/data") wg.Done() if err != nil { errNum++ } doneNum++ log.Infof("upload dir: %d/%d", doneNum, n) require.Nil(t, err) }(i) } wg.Wait() endTs := time.Now() duration := endTs.Sub(startTs).Milliseconds() fmt.Println(fmt.Sprintf("total: %d", n)) fmt.Println(fmt.Sprintf("errors: %d", errNum)) fmt.Println(fmt.Sprintf("error rate: %.3f", float32(errNum)/float32(n))) fmt.Println(fmt.Sprintf("duration: %dms", duration)) } func TestSeaweedFsManager_SyncRemoteToLocalPressure(t *testing.T) { var err error T.Setup(t) if _, err := os.Stat("./tmp/data"); err == nil { err = os.RemoveAll("./tmp/data") require.Nil(t, err) } err = T.m.UploadDir("./data", "/test/data") require.Nil(t, err) n := int(1e3) doneNum := 0 errNum := 0 startTs := time.Now() wg := sync.WaitGroup{} wg.Add(n) for i := 0; i < n; i++ { go func(i int) { err = T.m.SyncRemoteToLocal("/test/data", fmt.Sprintf("./tmp/data_%d", i)) wg.Done() if err != nil { errNum++ } doneNum++ log.Infof("updated: %d/%d", doneNum, n) require.Nil(t, err) }(i) } wg.Wait() endTs := time.Now() duration := endTs.Sub(startTs).Milliseconds() fmt.Println(fmt.Sprintf("total: %d", n)) fmt.Println(fmt.Sprintf("errors: %d", errNum)) fmt.Println(fmt.Sprintf("error rate: %.3f", float32(errNum)/float32(n))) fmt.Println(fmt.Sprintf("duration: %dms", duration)) } func TestSeaweedFsManager_UpdateFilePressure(t *testing.T) { var err error T.Setup(t) n := int(5e3) doneNum := 0 errNum := 0 startTs := time.Now() wg := sync.WaitGroup{} wg.Add(n) for i := 0; i < n; i++ { go func(i int) { err = T.m.UpdateFile(fmt.Sprintf("/test/data/test_data_%5d.txt", i), []byte(fmt.Sprintf("this is test data: %5d", i))) wg.Done() if err != nil { errNum++ } doneNum++ log.Infof("updated: %d/%d", doneNum, n) require.Nil(t, err) }(i) } wg.Wait() endTs := time.Now() duration := endTs.Sub(startTs).Milliseconds() fmt.Println(fmt.Sprintf("total: %d", n)) fmt.Println(fmt.Sprintf("errors: %d", errNum)) fmt.Println(fmt.Sprintf("error rate: %.3f", float32(errNum)/float32(n))) fmt.Println(fmt.Sprintf("duration: %dms", duration)) } ================================================ FILE: fs/test/utils.go ================================================ package test import ( "github.com/apex/log" "github.com/cenkalti/backoff/v4" "github.com/crawlab-team/crawlab/trace" "github.com/google/uuid" "io/ioutil" "os" "os/exec" "path" "path/filepath" "time" ) func init() { var err error TmpDir, err = filepath.Abs("tmp") if err != nil { panic(err) } if _, err := os.Stat(TmpDir); err != nil { if err := os.MkdirAll(TmpDir, os.ModePerm); err != nil { panic(err) } } //TmpDir = getTmpDir() } var TmpDir string func StartTestSeaweedFs() (err error) { // skip if CRAWLAB_IGNORE_WEED is set true if os.Getenv("CRAWLAB_IGNORE_WEED") != "" { return nil } // write to start.sh and stop.sh if err := writeShFiles(TmpDir); err != nil { return trace.TraceError(err) } // run weed go runCmd(exec.Command("sh", "./start.sh"), TmpDir) // wait for containers to be ready time.Sleep(5 * time.Second) f := func() error { _, err := T.m.ListDir("/", true) if err != nil { return err } return nil } b := backoff.WithMaxRetries(backoff.NewConstantBackOff(5*time.Second), 5) nt := func(err error, duration time.Duration) { log.Infof("seaweedfs services not ready, re-attempt in %.1f seconds", duration.Seconds()) } err = backoff.RetryNotify(f, b, nt) if err != nil { return trace.TraceError(err) } return nil } func StopTestSeaweedFs() (err error) { // skip if CRAWLAB_IGNORE_WEED is set true if os.Getenv("CRAWLAB_IGNORE_WEED") != "" { return nil } // stop seaweedfs if err := runCmd(exec.Command("sh", "./stop.sh"), TmpDir); err != nil { return trace.TraceError(err) } time.Sleep(5 * time.Second) // remove tmp folder if err := os.RemoveAll(TmpDir); err != nil { return trace.TraceError(err) } return nil } func writeShFiles(dirPath string) (err error) { fileNames := []string{ "start.sh", "stop.sh", } for _, fileName := range fileNames { data, err := Asset("bin/" + fileName) if err != nil { return trace.TraceError(err) } filePath := path.Join(dirPath, fileName) if err := ioutil.WriteFile(filePath, data, os.FileMode(0766)); err != nil { return trace.TraceError(err) } } return nil } func runCmd(cmd *exec.Cmd, dirPath string) (err error) { log.Infof("running cmd: %v", cmd) cmd.Dir = dirPath //cmd.Stdout = os.Stdout //cmd.Stderr = os.Stdout return cmd.Run() } func getTmpDir() string { id, _ := uuid.NewUUID() tmpDir := path.Join(os.TempDir(), id.String()) if _, err := os.Stat(tmpDir); err != nil { if err := os.MkdirAll(tmpDir, os.FileMode(0766)); err != nil { panic(err) } } return tmpDir } ================================================ FILE: fs/utils.go ================================================ package fs import ( "fmt" "github.com/crawlab-team/goseaweedfs" "net/url" "path/filepath" "regexp" "strings" ) func IsGitFile(file goseaweedfs.FileInfo) (res bool) { // skip .git res, err := regexp.MatchString("/?\\.git/", file.Path) if err != nil { return false } return res } func getCollectionAndTtlFromArgs(args ...interface{}) (collection, ttl string) { if len(args) > 0 { collection = args[0].(string) } if len(args) > 1 { ttl = args[1].(string) } return } func getUrlValuesFromArgs(args ...interface{}) (values url.Values) { if len(args) > 0 { values = args[0].(url.Values) } return values } func getFilesAndFilesMaps(f *goseaweedfs.Filer, localPath, remotePath string) (localFiles []goseaweedfs.FileInfo, remoteFiles []goseaweedfs.FilerFileInfo, localFilesMap map[string]goseaweedfs.FileInfo, remoteFilesMap map[string]goseaweedfs.FilerFileInfo, err error) { // declare maps localFilesMap = map[string]goseaweedfs.FileInfo{} remoteFilesMap = map[string]goseaweedfs.FilerFileInfo{} // cache local files info localFiles, err = goseaweedfs.ListFilesRecursive(localPath) if err != nil { return localFiles, remoteFiles, localFilesMap, remoteFilesMap, err } for _, file := range localFiles { fileRemotePath := fmt.Sprintf("%s%s", remotePath, strings.Replace(file.Path, localPath, "", -1)) localFilesMap[fileRemotePath] = file // directory dirRemotePath := filepath.Dir(fileRemotePath) _, ok := localFilesMap[dirRemotePath] if !ok { localFilesMap[dirRemotePath] = goseaweedfs.FileInfo{ Name: filepath.Base(dirRemotePath), Path: dirRemotePath, } } } // cache remote files info remoteFiles, err = f.ListDirRecursive(remotePath) if err != nil { if err.Error() != FilerResponseNotFoundErrorMessage { return localFiles, remoteFiles, localFilesMap, remoteFilesMap, err } err = nil } remoteFiles = getFlattenRemoteFiles(remoteFiles) for _, file := range remoteFiles { remoteFilesMap[file.FullPath] = file } return } func getFlattenRemoteFiles(files []goseaweedfs.FilerFileInfo) (flattenFiles []goseaweedfs.FilerFileInfo) { flattenFiles = []goseaweedfs.FilerFileInfo{} for _, file := range files { flattenFiles = append(flattenFiles, file) if file.IsDir { flattenFiles = append(flattenFiles, getFlattenRemoteFiles(file.Children)...) } } return } ================================================ FILE: go.work ================================================ go 1.22 use ( backend core db fs grpc template-parser trace vcs ) ================================================ FILE: go.work.sum ================================================ cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w= cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= cloud.google.com/go v0.113.0/go.mod h1:glEqlogERKYeePz6ZdkcLJ28Q2I6aERgDDErBg9GzO8= cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY= cloud.google.com/go v0.114.0/go.mod h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E= cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= cloud.google.com/go/accessapproval v1.7.5 h1:uzmAMSgYcnlHa9X9YSQZ4Q1wlfl4NNkZyQgho1Z6p04= cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= cloud.google.com/go/accessapproval v1.7.7 h1:vO95gvBi7qUgfA9SflexQs9hB4U4tnri/GwADIrLQy8= cloud.google.com/go/accessapproval v1.7.7/go.mod h1:10ZDPYiTm8tgxuMPid8s2DL93BfCt6xBh/Vg0Xd8pU0= cloud.google.com/go/accessapproval v1.7.9 h1:mp1X2FsNRdTYTVw4b6eF4OQ+7l6EpLnZlcatXiFWJTg= cloud.google.com/go/accessapproval v1.7.9/go.mod h1:teNI+P/xzZ3dppGXEYFvSmuOvmTjLE9toPq21WHssYc= cloud.google.com/go/accesscontextmanager v1.8.5 h1:2GLNaNu9KRJhJBFTIVRoPwk6xE5mUDgD47abBq4Zp/I= cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= cloud.google.com/go/accesscontextmanager v1.8.7 h1:GgdNoDwZR5RIO3j8XwXqa6Gc6q5mP3KYMdFC7FEVyG4= cloud.google.com/go/accesscontextmanager v1.8.7/go.mod h1:jSvChL1NBQ+uLY9zUBdPy9VIlozPoHptdBnRYeWuQoM= cloud.google.com/go/accesscontextmanager v1.8.9 h1:oVjc3eFQP92zezKsof5ly6ENhuNSsgadRdFKhUn7L9g= cloud.google.com/go/accesscontextmanager v1.8.9/go.mod h1:IXvQesVgOC7aXgK9OpYFn5eWnzz8fazegIiJ5WnCOVw= cloud.google.com/go/aiplatform v1.60.0 h1:0cSrii1ZeLr16MbBoocyy5KVnrSdiQ3KN/vtrTe7RqE= cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= cloud.google.com/go/aiplatform v1.67.0 h1:YWeqD4BjYwrmY4fa+isGcw0P81lJ3dKVxbWxdBchoiU= cloud.google.com/go/aiplatform v1.67.0/go.mod h1:s/sJ6btBEr6bKnrNWdK9ZgHCvwbZNdP90b3DDtxxw+Y= cloud.google.com/go/aiplatform v1.68.0 h1:EPPqgHDJpBZKRvv+OsB3cr0jYz3EL2pZ+802rBPcG8U= cloud.google.com/go/aiplatform v1.68.0/go.mod h1:105MFA3svHjC3Oazl7yjXAmIR89LKhRAeNdnDKJczME= cloud.google.com/go/analytics v0.23.0 h1:Q+y94XH84jM8SK8O7qiY/PJRexb6n7dRbQ6PiUa4YGM= cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= cloud.google.com/go/analytics v0.23.2 h1:O0fj88npvQFxg8LfXo7fArcSrC/wtAstGuWQ7dCHWjg= cloud.google.com/go/analytics v0.23.2/go.mod h1:vtE3olAXZ6edJYk1UOndEs6EfaEc9T2B28Y4G5/a7Fo= cloud.google.com/go/analytics v0.23.4 h1:5c425wSQBb+YAGr7ukgRFRAKa8SwlqTSapbb+CTJAEA= cloud.google.com/go/analytics v0.23.4/go.mod h1:1iTnQMOr6zRdkecW+gkxJpwV0Q/djEIII3YlXmyf7UY= cloud.google.com/go/apigateway v1.6.5 h1:sPXnpk+6TneKIrjCjcpX5YGsAKy3PTdpIchoj8/74OE= cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= cloud.google.com/go/apigateway v1.6.7 h1:DO5Vn3zmY1aDyfoqni8e8+x+lwrfLCoAAbEui9NB0y8= cloud.google.com/go/apigateway v1.6.7/go.mod h1:7wAMb/33Rzln+PrGK16GbGOfA1zAO5Pq6wp19jtIt7c= cloud.google.com/go/apigateway v1.6.9 h1:vxZBKroYYCplsNrjggtniokb83Rk9mDitaiBN9nppdQ= cloud.google.com/go/apigateway v1.6.9/go.mod h1:YE9XDTFwq859O6TpZNtatBMDWnMRZOiTVF+Ru3oCBeY= cloud.google.com/go/apigeeconnect v1.6.5 h1:CrfIKv9Go3fh/QfQgisU3MeP90Ww7l/sVGmr3TpECo8= cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= cloud.google.com/go/apigeeconnect v1.6.7 h1:z08Xuv7ZtaB2d4jsJi9/WhbnnI5s19wlLDZpssn3Fus= cloud.google.com/go/apigeeconnect v1.6.7/go.mod h1:hZxCKvAvDdKX8+eT0g5eEAbRSS9Gkzi+MPWbgAMAy5U= cloud.google.com/go/apigeeconnect v1.6.9 h1:WO8XlUGugxvdKBj5hQnv8l7+SsVXgJVA97iNXyFgUb8= cloud.google.com/go/apigeeconnect v1.6.9/go.mod h1:tl53uGgVG1A00qK1dF6wGIji0CQIMrLdNccJ6+R221U= cloud.google.com/go/apigeeregistry v0.8.3 h1:C+QU2K+DzDjk4g074ouwHQGkoff1h5OMQp6sblCVreQ= cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= cloud.google.com/go/apigeeregistry v0.8.5 h1:o1C/+IvzwYeV1doum61XmJQ/Bwpk/4+2DT1JyVu2x64= cloud.google.com/go/apigeeregistry v0.8.5/go.mod h1:ZMg60hq2K35tlqZ1VVywb9yjFzk9AJ7zqxrysOxLi3o= cloud.google.com/go/apigeeregistry v0.8.7 h1:K05SFNKzwvApZqVUcwg/6oFzn/b9WUrDN8pIdfD51qU= cloud.google.com/go/apigeeregistry v0.8.7/go.mod h1:Jge1HQaIkNU8JYSDY7l5SveeSKvGPvtLjzNjLU2+0N8= cloud.google.com/go/appengine v1.8.5 h1:l2SviT44zWQiOv8bPoMBzW0vOcMO22iO0s+nVtVhdts= cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= cloud.google.com/go/appengine v1.8.7 h1:qYrjEHEFY7+CL4QlHIHuwTgrTnZbSKzdPFqgjZDsQNo= cloud.google.com/go/appengine v1.8.7/go.mod h1:1Fwg2+QTgkmN6Y+ALGwV8INLbdkI7+vIvhcKPZCML0g= cloud.google.com/go/appengine v1.8.9 h1:rI/aezyrwereUE0i/umbA6rZIgpJpBImFcy3JJEcQd0= cloud.google.com/go/appengine v1.8.9/go.mod h1:sw8T321TAto/u6tMinv3AV63olGH/hw7RhG4ZgNhqFs= cloud.google.com/go/area120 v0.8.5 h1:vTs08KPLN/iMzTbxpu5ciL06KcsrVPMjz4IwcQyZ4uY= cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= cloud.google.com/go/area120 v0.8.7 h1:sUrR96yokdL6tTTXK0X13V1TLMta8/1u328bRG5lWZc= cloud.google.com/go/area120 v0.8.7/go.mod h1:L/xTq4NLP9mmxiGdcsVz7y1JLc9DI8pfaXRXbnjkR6w= cloud.google.com/go/area120 v0.8.9 h1:38uHviqcdB2S83yPfOXzDxf0KTG/W2DsXMuY/uf2T8c= cloud.google.com/go/area120 v0.8.9/go.mod h1:epLvbmajRp919r1LGdvS1zgcHJt/1MTQJJ9+r0/NBQc= cloud.google.com/go/artifactregistry v1.14.7 h1:W9sVlyb1VRcUf83w7aM3yMsnp4HS4PoyGqYQNG0O5lI= cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= cloud.google.com/go/artifactregistry v1.14.9 h1:SSvoD0ofOydm5gA1++15pW9VPgQbk0OmNlcb7JczoO4= cloud.google.com/go/artifactregistry v1.14.9/go.mod h1:n2OsUqbYoUI2KxpzQZumm6TtBgtRf++QulEohdnlsvI= cloud.google.com/go/artifactregistry v1.14.11 h1:NZzHn5lPKyi2kgtM9Atu6IBvqslL7Fu1+5EkOYZd+yk= cloud.google.com/go/artifactregistry v1.14.11/go.mod h1:ahyKXer42EOIddYzk2zYfvZnByGPdAYhXqBbRBsGizE= cloud.google.com/go/asset v1.17.2 h1:xgFnBP3luSbUcC9RWJvb3Zkt+y/wW6PKwPHr3ssnIP8= cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= cloud.google.com/go/asset v1.19.1 h1:mCqyoaDjDzaW1RqmmQtCJuawb9nca5bEu7HvVcpZDwg= cloud.google.com/go/asset v1.19.1/go.mod h1:kGOS8DiCXv6wU/JWmHWCgaErtSZ6uN5noCy0YwVaGfs= cloud.google.com/go/asset v1.19.3 h1:vl8wy3jpRa3ATctym5tiICp70iymSyOVbpKb3tKA668= cloud.google.com/go/asset v1.19.3/go.mod h1:1j8NNcHsbSE/KeHMZrizPIS6c8nm0WjEAPoFXzXNCj4= cloud.google.com/go/assuredworkloads v1.11.5 h1:gCrN3IyvqY3cP0wh2h43d99CgH3G+WYs9CeuFVKChR8= cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= cloud.google.com/go/assuredworkloads v1.11.7 h1:xieyFA+JKyTDkO/Z9UyVEpkHW8pDYykU51O4G0pvXEg= cloud.google.com/go/assuredworkloads v1.11.7/go.mod h1:CqXcRH9N0KCDtHhFisv7kk+cl//lyV+pYXGi1h8rCEU= cloud.google.com/go/assuredworkloads v1.11.9 h1:xMjLtM24zy8yWGZlNtYxXo9fBj7ArWTsNkXKlRBZlqw= cloud.google.com/go/assuredworkloads v1.11.9/go.mod h1:uZ6+WHiT4iGn1iM1wk5njKnKJWiM3v/aYhDoCoHxs1w= cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro= cloud.google.com/go/auth v0.4.2 h1:sb0eyLkhRtpq5jA+a8KWw0W70YcdVca7KJ8TM0AFYDg= cloud.google.com/go/auth v0.4.2/go.mod h1:Kqvlz1cf1sNA0D+sYJnkPQOP+JMHkuHeIgVmCRtZOLc= cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.13.5 h1:ijiJy9sYWh75WrqImXsfWc1e3HR3iO+ef9fvW03Ig/4= cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= cloud.google.com/go/automl v1.13.7 h1:w9AyogtMLXbcy5kzXPvk/Q3MGQkgJH7ZDB8fAUUxTt8= cloud.google.com/go/automl v1.13.7/go.mod h1:E+s0VOsYXUdXpq0y4gNZpi0A/s6y9+lAarmV5Eqlg40= cloud.google.com/go/automl v1.13.9 h1:GzYpU33Zo2tQ+8amLasjeBPawpKfBYnLGHVMQcyiFv4= cloud.google.com/go/automl v1.13.9/go.mod h1:KECCWW2AFsRuEVxUJEIXxcm3yPLf1rxS+qsBamyacMc= cloud.google.com/go/baremetalsolution v1.2.4 h1:LFydisRmS7hQk9P/YhekwuZGqb45TW4QavcrMToWo5A= cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= cloud.google.com/go/baremetalsolution v1.2.6 h1:W4oSMS6vRCo9DLr1RPyDP8oeLverbvhJRzaZSsipft8= cloud.google.com/go/baremetalsolution v1.2.6/go.mod h1:KkS2BtYXC7YGbr42067nzFr+ABFMs6cxEcA1F+cedIw= cloud.google.com/go/baremetalsolution v1.2.8 h1:mM8zaxertfV5gaNGloJdJY87z7l8WcNkhw96VB1IGTQ= cloud.google.com/go/baremetalsolution v1.2.8/go.mod h1:Ai8ENs7ADMYWQ45DtfygUc6WblhShfi3kNPvuGv8/ok= cloud.google.com/go/batch v1.8.0 h1:2HK4JerwVaIcCh/lJiHwh6+uswPthiMMWhiSWLELayk= cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= cloud.google.com/go/batch v1.8.7 h1:zaQwOAd7TlE84pwPHavNMsnv5zRyRV8ym2DJ4iQ2cV0= cloud.google.com/go/batch v1.8.7/go.mod h1:O5/u2z8Wc7E90Bh4yQVLQIr800/0PM5Qzvjac3Jxt4k= cloud.google.com/go/batch v1.9.0 h1:WlOqpQMOtWvOLIs7vCxBwYZGaB76i3olsBCVUvszY3M= cloud.google.com/go/batch v1.9.0/go.mod h1:VhRaG/bX2EmeaPSHvtptP5OAhgYuTrvtTAulKM68oiI= cloud.google.com/go/beyondcorp v1.0.4 h1:qs0J0O9Ol2h1yA0AU+r7l3hOCPzs2MjE1d6d/kaHIKo= cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= cloud.google.com/go/beyondcorp v1.0.6 h1:KBcujO3QRvBIwzZLtvQEPB9SXdovHnMBx0V/uhucH9o= cloud.google.com/go/beyondcorp v1.0.6/go.mod h1:wRkenqrVRtnGFfnyvIg0zBFUdN2jIfeojFF9JJDwVIA= cloud.google.com/go/beyondcorp v1.0.8 h1:Dw9VO8fzZ2GWsfgx4wST03hjaZmRNv09lt0GZuzyVxM= cloud.google.com/go/beyondcorp v1.0.8/go.mod h1:2WaEvUnw+1ZIUNu227h71X/Q8ypcWWowii9TQ4xlfo0= cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= cloud.google.com/go/bigquery v1.59.1 h1:CpT+/njKuKT3CEmswm6IbhNu9u35zt5dO4yPDLW+nG4= cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= cloud.google.com/go/bigquery v1.61.0 h1:w2Goy9n6gh91LVi6B2Sc+HpBl8WbWhIyzdvVvrAuEIw= cloud.google.com/go/bigquery v1.61.0/go.mod h1:PjZUje0IocbuTOdq4DBOJLNYB0WF3pAKBHzAYyxCwFo= cloud.google.com/go/billing v1.18.2 h1:oWUEQvuC4JvtnqLZ35zgzdbuHt4Itbftvzbe6aEyFdE= cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= cloud.google.com/go/billing v1.18.5 h1:GbOg1uGvoV8FXxMStFoNcq5z9AEUwCpKt/6GNcuDSZM= cloud.google.com/go/billing v1.18.5/go.mod h1:lHw7fxS6p7hLWEPzdIolMtOd0ahLwlokW06BzbleKP8= cloud.google.com/go/billing v1.18.7 h1:1Y7DdC2i8JQctWpd1ycra5iK+2LzwgFi+TxTqF3Yyp8= cloud.google.com/go/billing v1.18.7/go.mod h1:RreCBJPmaN/lzCz/2Xl1hA+OzWGqrzDsax4Qjjp0CbA= cloud.google.com/go/binaryauthorization v1.8.1 h1:1jcyh2uIUwSZkJ/JmL8kd5SUkL/Krbv8zmYLEbAz6kY= cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= cloud.google.com/go/binaryauthorization v1.8.3 h1:RHnEM4HXbWShlGhPA0Jzj2YYETCHxmisNMU0OE2fXQM= cloud.google.com/go/binaryauthorization v1.8.3/go.mod h1:Cul4SsGlbzEsWPOz2sH8m+g2Xergb6ikspUyQ7iOThE= cloud.google.com/go/binaryauthorization v1.8.5 h1:ly5gQoJGHbuOM7E+pND38pTiQ0pZ4zTEOfJlfyfIIew= cloud.google.com/go/binaryauthorization v1.8.5/go.mod h1:2npTMgNJPsmUg0jfmDDORuqBkTPEW6ZSTHXzfxTvN1M= cloud.google.com/go/certificatemanager v1.7.5 h1:UMBr/twXvH3jcT5J5/YjRxf2tvwTYIfrpemTebe0txc= cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= cloud.google.com/go/certificatemanager v1.8.1 h1:XURrQhj5COWAEvICivbGID/Hu67AvMYHAhMRIyc3Ux8= cloud.google.com/go/certificatemanager v1.8.1/go.mod h1:hDQzr50Vx2gDB+dOfmDSsQzJy/UPrYRdzBdJ5gAVFIc= cloud.google.com/go/certificatemanager v1.8.3 h1:feyxS5Q8eWQNXQcVAcdooQEKGT/1B/qCcYvamOen7fc= cloud.google.com/go/certificatemanager v1.8.3/go.mod h1:QS0jxTu5wgEbzaYgGs/GBYKvVgAgc9jnYaaTFH8jRtE= cloud.google.com/go/channel v1.17.5 h1:/omiBnyFjm4S1ETHoOmJbL7LH7Ljcei4rYG6Sj3hc80= cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= cloud.google.com/go/channel v1.17.7 h1:PrplNaAS6Dn187e+OcGzyEKETX8iL3tCaDqcPPW7Zoo= cloud.google.com/go/channel v1.17.7/go.mod h1:b+FkgBrhMKM3GOqKUvqHFY/vwgp+rwsAuaMd54wCdN4= cloud.google.com/go/channel v1.17.9 h1:rqF5CjW6KnOmlVZ75PNkuXYh5nh8dIsIWQjHLLwPy3Y= cloud.google.com/go/channel v1.17.9/go.mod h1:h9emIJm+06sK1FxqC3etsWdG87tg92T24wimlJs6lhY= cloud.google.com/go/cloudbuild v1.15.1 h1:ZB6oOmJo+MTov9n629fiCrO9YZPOg25FZvQ7gIHu5ng= cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= cloud.google.com/go/cloudbuild v1.16.1 h1:zkCG1dBezxRM3dtgQ9h1Y+IJ7V+lARWgp0l9k/SZsfU= cloud.google.com/go/cloudbuild v1.16.1/go.mod h1:c2KUANTtCBD8AsRavpPout6Vx8W+fsn5zTsWxCpWgq4= cloud.google.com/go/cloudbuild v1.16.3 h1:BIT0cFWQDT4XTVMyyZsjXvltVqBwvJ/RAKIRBqkgXf0= cloud.google.com/go/cloudbuild v1.16.3/go.mod h1:KJYZAwTUaDKDdEHwLj/EmnpmwLkMuq+fGnBEHA1LlE4= cloud.google.com/go/clouddms v1.7.4 h1:Sr0Zo5EAcPQiCBgHWICg3VGkcdS/LLP1d9SR7qQBM/s= cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= cloud.google.com/go/clouddms v1.7.6 h1:Q47KKoA0zsNcC9U5aCmop5TPPItVq4cx7Wwqgra+5PU= cloud.google.com/go/clouddms v1.7.6/go.mod h1:8HWZ2tznZ0mNAtTpfnRNT0QOThqn9MBUqTj0Lx8npIs= cloud.google.com/go/clouddms v1.7.8 h1:WEz8ECgv4ZinRc84xcW1wTsFfLNb60yrSsIdsEJFRDk= cloud.google.com/go/clouddms v1.7.8/go.mod h1:KQpBMxH99ZTPK4LgXkYUntzRQ5hcNkjpGRbNSRzW9Nk= cloud.google.com/go/cloudtasks v1.12.6 h1:EUt1hIZ9bLv8Iz9yWaCrqgMnIU+Tdh0yXM1MMVGhjfE= cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= cloud.google.com/go/cloudtasks v1.12.8 h1:Y0HUuiCAVk9BojLItOycBl91tY25NXH8oFsyi1IC/U4= cloud.google.com/go/cloudtasks v1.12.8/go.mod h1:aX8qWCtmVf4H4SDYUbeZth9C0n9dBj4dwiTYi4Or/P4= cloud.google.com/go/cloudtasks v1.12.10 h1:2mdGqvYFm9HwPh//ckbcX8mZJgyG+F1TWk+82+eLuwM= cloud.google.com/go/cloudtasks v1.12.10/go.mod h1:OHJzRAdE+7H00cdsINhb21ugVLDgk3Uh4r0holCB5XQ= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute v1.27.0 h1:EGawh2RUnfHT5g8f/FX3Ds6KZuIBC77hZoDrBvEZw94= cloud.google.com/go/compute v1.27.0/go.mod h1:LG5HwRmWFKM2C5XxHRiNzkLLXW48WwvyVC0mfWsYPOM= cloud.google.com/go/compute v1.27.2 h1:5cE5hdrwJV/92ravlwIFRGnyH9CpLGhh4N0ZDVTU+BA= cloud.google.com/go/compute v1.27.2/go.mod h1:YQuHkNEwP3bIz4LBYQqf4DIMfFtTDtnEgnwG0mJQQ9I= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/contactcenterinsights v1.13.0 h1:6Vs/YnDG5STGjlWMEjN/xtmft7MrOTOnOZYUZtGTx0w= cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= cloud.google.com/go/contactcenterinsights v1.13.2 h1:46ertIh+cGkTg/lN7fN+TOx09SoM65dpdUp96vXBcMY= cloud.google.com/go/contactcenterinsights v1.13.2/go.mod h1:AfkSB8t7mt2sIY6WpfO61nD9J9fcidIchtxm9FqJVXk= cloud.google.com/go/contactcenterinsights v1.13.4 h1:BvtC33BbX+3p+v+VB0AZ6djRrcXP+qPqfWsIR+kz5v8= cloud.google.com/go/contactcenterinsights v1.13.4/go.mod h1:6OWSyQxeaQRxhkyMhtE+RFOOlsMcKOTukv8nnjxbNCQ= cloud.google.com/go/container v1.31.0 h1:MAaNH7VRNPWEhvqOypq2j+7ONJKrKzon4v9nS3nLZe0= cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= cloud.google.com/go/container v1.35.1 h1:Vbu/3PZNrgV1Z5DGcRubQdUccX/uMUDNc+NgHNIfbEk= cloud.google.com/go/container v1.35.1/go.mod h1:udm8fgLm3TtpnjFN4QLLjZezAIIp/VnMo316yIRVRQU= cloud.google.com/go/container v1.37.2 h1:g5zm1SUBZ+q7IvtI5hM/6xcpf2C/bFfN2EXzS07Iz9k= cloud.google.com/go/container v1.37.2/go.mod h1:2ly7zpBmWtYjjuoB3fHyq8Gqrxaj2NIwzwVRpUcKYXk= cloud.google.com/go/containeranalysis v0.11.4 h1:doJ0M1ljS4hS0D2UbHywlHGwB7sQLNrt9vFk9Zyi7vY= cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= cloud.google.com/go/containeranalysis v0.11.6 h1:mSrneOVadcpnDZHJebg+ts/10azGTUKOCSQET7KdT7g= cloud.google.com/go/containeranalysis v0.11.6/go.mod h1:YRf7nxcTcN63/Kz9f86efzvrV33g/UV8JDdudRbYEUI= cloud.google.com/go/containeranalysis v0.11.8 h1:1rkYgK2szbRH311mRw/3lkeEOqrjN+2gOD7AZhMUxZw= cloud.google.com/go/containeranalysis v0.11.8/go.mod h1:2ru4oxs6dCcaG3ZsmKAy4yMmG68ukOuS/IRCMEHYpLo= cloud.google.com/go/datacatalog v1.19.3 h1:A0vKYCQdxQuV4Pi0LL9p39Vwvg4jH5yYveMv50gU5Tw= cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= cloud.google.com/go/datacatalog v1.20.1 h1:czcba5mxwRM5V//jSadyig0y+8aOHmN7gUl9GbHu59E= cloud.google.com/go/datacatalog v1.20.1/go.mod h1:Jzc2CoHudhuZhpv78UBAjMEg3w7I9jHA11SbRshWUjk= cloud.google.com/go/datacatalog v1.20.3 h1:lzMtWaUlaz9Bd9anvq2KBZwcFujzhVuxhIz1MsqRJv8= cloud.google.com/go/datacatalog v1.20.3/go.mod h1:AKC6vAy5urnMg5eJK3oUjy8oa5zMbiY33h125l8lmlo= cloud.google.com/go/dataflow v0.9.5 h1:RYHtcPhmE664+F0Je46p+NvFbG8z//KCXp+uEqB4jZU= cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= cloud.google.com/go/dataflow v0.9.7 h1:wKEakCbRevlwsWqTn34pWJUFmdbx0HKwpRH6HhU7NIs= cloud.google.com/go/dataflow v0.9.7/go.mod h1:3BjkOxANrm1G3+/EBnEsTEEgJu1f79mFqoOOZfz3v+E= cloud.google.com/go/dataflow v0.9.9 h1:7qTWGXfpM2z3assRznIXJLw+XJNlucHFcvFAYhclQ+o= cloud.google.com/go/dataflow v0.9.9/go.mod h1:Wk/92E1BvhV7qs/dWb+3dN26uGgyp/H1Jr5ZJxeD3dw= cloud.google.com/go/dataform v0.9.2 h1:5e4eqGrd0iDTCg4Q+VlAao5j2naKAA7xRurNtwmUknU= cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= cloud.google.com/go/dataform v0.9.4 h1:MiK1Us7YP9+sdNViUE4X2B2vLScrKcjOPw5b6uamZvE= cloud.google.com/go/dataform v0.9.4/go.mod h1:jjo4XY+56UrNE0wsEQsfAw4caUs4DLJVSyFBDelRDtQ= cloud.google.com/go/dataform v0.9.6 h1:8BMoPO9CD3qmPqnunVi73JcvwQrkjLILPXZKFExsjZc= cloud.google.com/go/dataform v0.9.6/go.mod h1:JKDPMfcYMu9oUMubIvvAGWTBX0sw4o/JIjCcczzbHmk= cloud.google.com/go/datafusion v1.7.5 h1:HQ/BUOP8OIGJxuztpYvNvlb+/U+/Bfs9SO8tQbh61fk= cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= cloud.google.com/go/datafusion v1.7.7 h1:ViFnMnUK7LNcWvisZgihxXit76JxSHFeijYI5U/gjOE= cloud.google.com/go/datafusion v1.7.7/go.mod h1:qGTtQcUs8l51lFA9ywuxmZJhS4ozxsBSus6ItqCUWMU= cloud.google.com/go/datafusion v1.7.9 h1:ZwicZskyu64L8Y6+zvZQjIav5A1xYwM0nqpk88HKLmY= cloud.google.com/go/datafusion v1.7.9/go.mod h1:ciYV8FL0JmrwgoJ7CH64oUHiI0oOf2VLE45LWKT51Ls= cloud.google.com/go/datalabeling v0.8.5 h1:GpIFRdm0qIZNsxqURFJwHt0ZBJZ0nF/mUVEigR7PH/8= cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= cloud.google.com/go/datalabeling v0.8.7 h1:M6irSHns6VxMro+IbvDxDJLD6tkfjlW+mo2MPaM23KA= cloud.google.com/go/datalabeling v0.8.7/go.mod h1:/PPncW5gxrU15UzJEGQoOT3IobeudHGvoExrtZ8ZBwo= cloud.google.com/go/datalabeling v0.8.9 h1:4ndOrLlhYErzhJGciRJx+s33+6P4cS23GnROnfaJ6hE= cloud.google.com/go/datalabeling v0.8.9/go.mod h1:61QutR66VZFgN8boHhl4/FTfxenNzihykv18BgxwSrg= cloud.google.com/go/dataplex v1.14.2 h1:fxIfdU8fxzR3clhOoNI7XFppvAmndxDu1AMH+qX9WKQ= cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= cloud.google.com/go/dataplex v1.16.0 h1:e8SV0yKuSjgHEZaQcZwjKXe0ta1jZrvLxX/2i/IAG+8= cloud.google.com/go/dataplex v1.16.0/go.mod h1:OlBoytuQ56+7aUCC03D34CtoF/4TJ5SiIrLsBdDu87Q= cloud.google.com/go/dataplex v1.18.0 h1:kXCHm9TqTr5BhZnsSD32iCRmf1S+Hho+UDqXr3Gdw7s= cloud.google.com/go/dataplex v1.18.0/go.mod h1:THLDVG07lcY1NgqVvjTV1mvec+rFHwpDwvSd+196MMc= cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= cloud.google.com/go/dataproc/v2 v2.4.0 h1:/u81Fd+BvCLp+xjctI1DiWVJn6cn9/s3Akc8xPH02yk= cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= cloud.google.com/go/dataproc/v2 v2.4.2 h1:RNMG5ffWKdbWOkwvjC4GqxLaxEaWFpm2hQCF2WFW/vo= cloud.google.com/go/dataproc/v2 v2.4.2/go.mod h1:smGSj1LZP3wtnsM9eyRuDYftNAroAl6gvKp/Wk64XDE= cloud.google.com/go/dataproc/v2 v2.5.1 h1:AYq1wJCKHrSG4KtxMQPkn1b0/uaHULHbXXTukCgou90= cloud.google.com/go/dataproc/v2 v2.5.1/go.mod h1:5s2CuQyTPX7e19ZRMLicfPFNgXrvsVct3xz94UvWFeQ= cloud.google.com/go/dataqna v0.8.5 h1:9ybXs3nr9BzxSGC04SsvtuXaHY0qmJSLIpIAbZo9GqQ= cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= cloud.google.com/go/dataqna v0.8.7 h1:qM60MGNTGsSJuzAziVJjtRA7pGby2dA8OuqdVRe/lYo= cloud.google.com/go/dataqna v0.8.7/go.mod h1:hvxGaSvINAVH5EJJsONIwT1y+B7OQogjHPjizOFoWOo= cloud.google.com/go/dataqna v0.8.9 h1:7kiDfd4c/pSW8jmeeOac/H+PYgwLrIt4L88s4JiFRZU= cloud.google.com/go/dataqna v0.8.9/go.mod h1:wrw1SL/zLRlVgf0d8P0ZBJ2hhGaLbwoNRsW6m1mn64g= cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.15.0 h1:0P9WcsQeTWjuD1H14JIY7XQscIPQ4Laje8ti96IC5vg= cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= cloud.google.com/go/datastore v1.17.0 h1:UEmzuUdyDE58HV2jcb0BoqwCAwsJS2mtHapCsMmhVh0= cloud.google.com/go/datastore v1.17.0/go.mod h1:RiRZU0G6VVlIVlv1HRo3vSAPFHULV0ddBNsXO+Sony4= cloud.google.com/go/datastore v1.17.1 h1:6Me8ugrAOAxssGhSo8im0YSuy4YvYk4mbGvCadAH5aE= cloud.google.com/go/datastore v1.17.1/go.mod h1:mtzZ2HcVtz90OVrEXXGDc2pO4NM1kiBQy8YV4qGe0ZM= cloud.google.com/go/datastream v1.10.4 h1:o1QDKMo/hk0FN7vhoUQURREuA0rgKmnYapB+1M+7Qz4= cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= cloud.google.com/go/datastream v1.10.6 h1:FfNUy9j3aRQ99L4a5Rdm82RMuiw0BIe3lpPn2ykom8k= cloud.google.com/go/datastream v1.10.6/go.mod h1:lPeXWNbQ1rfRPjBFBLUdi+5r7XrniabdIiEaCaAU55o= cloud.google.com/go/datastream v1.10.8 h1:INvIDTnuti68Lmdizp2GUyRFjN9k3X7IowX0Ixy9Vto= cloud.google.com/go/datastream v1.10.8/go.mod h1:6nkPjnk5Qr602Wq+YQ+/RWUOX5h4voMTz5abgEOYPCM= cloud.google.com/go/deploy v1.17.1 h1:m27Ojwj03gvpJqCbodLYiVmE9x4/LrHGGMjzc0LBfM4= cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= cloud.google.com/go/deploy v1.19.0 h1:fzbObuGgoViO0ArFuOQIJ2yr5bH5YzbORVvMDBrDC5I= cloud.google.com/go/deploy v1.19.0/go.mod h1:BW9vAujmxi4b/+S7ViEuYR65GiEsqL6Mhf5S/9TeDRU= cloud.google.com/go/deploy v1.19.2 h1:C8T/Hna2lDE8qbwP75G+iJclnrIj7oblBoQoc1cfDWc= cloud.google.com/go/deploy v1.19.2/go.mod h1:i6zfU9FZkqFgWIvO2/gsodGU9qF4tF9mBgoMdfnf6as= cloud.google.com/go/dialogflow v1.49.0 h1:KqG0oxGE71qo0lRVyAoeBozefCvsMfcDzDjoLYSY0F4= cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= cloud.google.com/go/dialogflow v1.53.0 h1:C9wQ0odRYQsar0XqwCQb0c13BkRBsoSjOaejOg5ntgQ= cloud.google.com/go/dialogflow v1.53.0/go.mod h1:LqAvxq7bXiiGC3/DWIz9XXCxth2z2qpSnBAAmlNOj6U= cloud.google.com/go/dialogflow v1.54.2 h1:uS7IDkXIUR5EduLfyPmgTpZ27RcUIHby7JKsk4fBPdo= cloud.google.com/go/dialogflow v1.54.2/go.mod h1:avkFNYog+U127jKpGzW1FOllBwZy3OfCz1K1eE9RGh8= cloud.google.com/go/dlp v1.11.2 h1:lTipOuJaSjlYnnotPMbEhKURLC6GzCMDDzVbJAEbmYM= cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= cloud.google.com/go/dlp v1.14.0 h1:/GQVl5gOPR2dUemrR2YJxZG5D9MCE3AYgmDxjzP54jI= cloud.google.com/go/dlp v1.14.0/go.mod h1:4fvEu3EbLsHrgH3QFdFlTNIiCP5mHwdYhS/8KChDIC4= cloud.google.com/go/dlp v1.14.2 h1:oR15Jcd/grn//eftZ/B0DJ99lTaeN8vOf8TK5xhKEvc= cloud.google.com/go/dlp v1.14.2/go.mod h1:+uwRt+6wZ3PL0wsmZ1cUAj0Mt9kyeV3WcIKPW03wJVU= cloud.google.com/go/documentai v1.25.0 h1:lI62GMEEPO6vXJI9hj+G9WjOvnR0hEjvjokrnex4cxA= cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= cloud.google.com/go/documentai v1.30.0 h1:6KI6P04WExzrfbciW5RTEQScBEY98Fc4VtS04ufT3Js= cloud.google.com/go/documentai v1.30.0/go.mod h1:3Qt8PMt3S8W6w3VeoYFraaMS2GJRrXFnvkyn+GpB1n0= cloud.google.com/go/documentai v1.30.3 h1:D75r7hqnc9Zz6aRV8fzs/1V94R5YIv+FDJivUT4r+n4= cloud.google.com/go/documentai v1.30.3/go.mod h1:aMxiOouLr36hyahLhI3OwAcsy7plOTiXR/RmK+MHbSg= cloud.google.com/go/domains v0.9.5 h1:Mml/R6s3vQQvFPpi/9oX3O5dRirgjyJ8cksK8N19Y7g= cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= cloud.google.com/go/domains v0.9.7 h1:IixFIMRzUJWZUAOe8s/K2X4Bvtp0A3xjHLljfNC4aSo= cloud.google.com/go/domains v0.9.7/go.mod h1:u/yVf3BgfPJW3QDZl51qTJcDXo9PLqnEIxfGmGgbHEc= cloud.google.com/go/domains v0.9.9 h1:kIqgwkIph6Mw+m1nWafdEBrGqPPZ1J98hqO11gkL4BM= cloud.google.com/go/domains v0.9.9/go.mod h1:/ewEPIaNmTrElY7u9BZPcLPnoP1NJJXGvISDDapwVNU= cloud.google.com/go/edgecontainer v1.1.5 h1:tBY32km78ScpK2aOP84JoW/+wtpx5WluyPUSEE3270U= cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= cloud.google.com/go/edgecontainer v1.2.1 h1:xa6MIQhGylE24QdWaxhfIfAJE3Pupcr+i77WEx3NJrg= cloud.google.com/go/edgecontainer v1.2.1/go.mod h1:OE2D0lbkmGDVYLCvpj8Y0M4a4K076QB7E2JupqOR/qU= cloud.google.com/go/edgecontainer v1.2.3 h1:F5UsQ/A4GjkV9dTBi3KMFGXPa/6OdTk5/Dce2bdYonM= cloud.google.com/go/edgecontainer v1.2.3/go.mod h1:gMKe2JfE0OT0WuCJArzIndAmMWDPCIYGSWYIpJ6M7oM= cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= cloud.google.com/go/errorreporting v0.3.1 h1:E/gLk+rL7u5JZB9oq72iL1bnhVlLrnfslrgcptjJEUE= cloud.google.com/go/errorreporting v0.3.1/go.mod h1:6xVQXU1UuntfAf+bVkFk6nld41+CPyF2NSPCyXE3Ztk= cloud.google.com/go/essentialcontacts v1.6.6 h1:13eHn5qBnsawxI7mIrv4jRIEmQ1xg0Ztqw5ZGqtUNfA= cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= cloud.google.com/go/essentialcontacts v1.6.8 h1:p5Y7ZNVPiV9pEAHzvWiPcSiQRMQqcuHxOP0ZOP0vVww= cloud.google.com/go/essentialcontacts v1.6.8/go.mod h1:EHONVDSum2xxG2p+myyVda/FwwvGbY58ZYC4XqI/lDQ= cloud.google.com/go/essentialcontacts v1.6.10 h1:zI+3LgjRcv7StB7O35sWqCg79OKDx5sRR4GAq36fi+s= cloud.google.com/go/essentialcontacts v1.6.10/go.mod h1:wQlXvEb/0hB0C0d4H6/90P8CiZcYewkvJ3VoUVFPi4E= cloud.google.com/go/eventarc v1.13.4 h1:ORkd6/UV5FIdA8KZQDLNZYKS7BBOrj0p01DXPmT4tE4= cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= cloud.google.com/go/eventarc v1.13.6 h1:we+qx5uCZ88aQzQS3MJXRvAh/ik+EmqVyjcW1oYFW44= cloud.google.com/go/eventarc v1.13.6/go.mod h1:QReOaYnDNdjwAQQWNC7nfr63WnaKFUw7MSdQ9PXJYj0= cloud.google.com/go/eventarc v1.13.8 h1:2sbz7e95cv6zm2mNrMJlAQ6J93qQsGCQzw4lYa5GWJQ= cloud.google.com/go/eventarc v1.13.8/go.mod h1:Xq3SsMoOAn7RmacXgJO7kq818iRLFF0bVhH780qlmTs= cloud.google.com/go/filestore v1.8.1 h1:X5G4y/vrUo1B8Nsz93qSWTMAcM8LXbGUldq33OdcdCw= cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= cloud.google.com/go/filestore v1.8.3 h1:CpRnsUpMU5gxUKyfh7TD0SM+E+7E4ORaDea2JctKfpY= cloud.google.com/go/filestore v1.8.3/go.mod h1:QTpkYpKBF6jlPRmJwhLqXfJQjVrQisplyb4e2CwfJWc= cloud.google.com/go/filestore v1.8.5 h1:yAHY3pGq6/IX4sLQqPpfaqfnSk1LmCdVkWNwzIP4X7c= cloud.google.com/go/filestore v1.8.5/go.mod h1:o8KvHyl5V30kIdrPX6hE+RknscXCUFXWSxYsEWeFfRU= cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= cloud.google.com/go/functions v1.16.0 h1:IWVylmK5F6hJ3R5zaRW7jI5PrWhCvtBVU4axQLmXSo4= cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= cloud.google.com/go/functions v1.16.2 h1:83bd2lCgtu2nLbX2jrqsrQhIs7VuVA1N6Op5syeRVIg= cloud.google.com/go/functions v1.16.2/go.mod h1:+gMvV5E3nMb9EPqX6XwRb646jTyVz8q4yk3DD6xxHpg= cloud.google.com/go/functions v1.16.4 h1:+mNEYegIO1ToQXsWEhEI6cI1lm+VAeu0pAmc+atYOaY= cloud.google.com/go/functions v1.16.4/go.mod h1:uDp5MbH0kCtXe3uBluq3Zi7bEDuHqcn60mAHxUsNezI= cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= cloud.google.com/go/gkebackup v1.3.5 h1:iuE8KNtTsPOc79qeWoNS8zOWoXPD9SAdOmwgxtlCmh8= cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= cloud.google.com/go/gkebackup v1.5.0 h1:wysUXEkggPwENZY3BXroOyWoyVfPypzaqNHgOZD9Kck= cloud.google.com/go/gkebackup v1.5.0/go.mod h1:eLaf/+n8jEmIvOvDriGjo99SN7wRvVadoqzbZu0WzEw= cloud.google.com/go/gkebackup v1.5.2 h1:sdGeTG6O+JPI7rRiVNy7wO4r4CELChfNe7C8BWPOJRM= cloud.google.com/go/gkebackup v1.5.2/go.mod h1:ZuWJKacdXtjiO8ry9RrdT57gvcsU7c7/FTqqwjdNUjk= cloud.google.com/go/gkeconnect v0.8.5 h1:17d+ZSSXKqG/RwZCq3oFMIWLPI8Zw3b8+a9/BEVlwH0= cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= cloud.google.com/go/gkeconnect v0.8.7 h1:BfXsTXYs5xlicAlgbtlo8Cw+YdzU3PrlBg7dATJUwrk= cloud.google.com/go/gkeconnect v0.8.7/go.mod h1:iUH1jgQpTyNFMK5LgXEq2o0beIJ2p7KKUUFerkf/eGc= cloud.google.com/go/gkeconnect v0.8.9 h1:cXA4NWFlB174ub2kIaGLGrKxgTFjDWPzEs766i6Frww= cloud.google.com/go/gkeconnect v0.8.9/go.mod h1:gl758q5FLXewQZIsxQ7vHyYmLcGBuubvQO6J3yFDh08= cloud.google.com/go/gkehub v0.14.5 h1:RboLNFzf9wEMSo7DrKVBlf+YhK/A/jrLN454L5Tz99Q= cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= cloud.google.com/go/gkehub v0.14.7 h1:bHwcvgh8AmcYm6p6/ZrWW3a7J7sKBDtqtsyVXKssnPs= cloud.google.com/go/gkehub v0.14.7/go.mod h1:NLORJVTQeCdxyAjDgUwUp0A6BLEaNLq84mCiulsM4OE= cloud.google.com/go/gkehub v0.14.9 h1:fWHBKtPwH7Wp5JjNxlPLanYYmXj6XuHjIRk6oa4yqkY= cloud.google.com/go/gkehub v0.14.9/go.mod h1:W2rDU2n2xgMpf3/BqpT6ffUX/I8yez87rrW/iGRz6Kk= cloud.google.com/go/gkemulticloud v1.1.1 h1:rsSZAGLhyjyE/bE2ToT5fqo1qSW7S+Ubsc9jFOcbhSI= cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= cloud.google.com/go/gkemulticloud v1.2.0 h1:zaWBakKPT6mPHVn5iefuRqttjpbNsb8LlMw9KgfyfyU= cloud.google.com/go/gkemulticloud v1.2.0/go.mod h1:iN5wBxTLPR6VTBWpkUsOP2zuPOLqZ/KbgG1bZir1Cng= cloud.google.com/go/gkemulticloud v1.2.2 h1:Msgg//raevqYlNZ+N8HFfO707wYVCyUnPKQPkt1g288= cloud.google.com/go/gkemulticloud v1.2.2/go.mod h1:VMsMYDKpUVYNrhese31TVJMVXPLEtFT/AnIarqlcwVo= cloud.google.com/go/grafeas v0.3.4 h1:D4x32R/cHX3MTofKwirz015uEdVk4uAxvZkZCZkOrF4= cloud.google.com/go/grafeas v0.3.4/go.mod h1:A5m316hcG+AulafjAbPKXBO/+I5itU4LOdKO2R/uDIc= cloud.google.com/go/grafeas v0.3.5 h1:Z87HxC4vnjR1kWWtzP6BuQXa6xBmndRK/kaz4iu6oMA= cloud.google.com/go/grafeas v0.3.5/go.mod h1:y54iTBcI+lgUdI+kAPKb8jtPqeTkA2dsYzWSrQtpc5s= cloud.google.com/go/grafeas v0.3.6 h1:7bcA10EBgTsxeAVypJhz2Dv3fhrdlO7Ml8l7ZZA2IkE= cloud.google.com/go/grafeas v0.3.6/go.mod h1:to6ECAPgRO2xeqD8ISXHc70nObJuaKZThreQOjeOH3o= cloud.google.com/go/gsuiteaddons v1.6.5 h1:CZEbaBwmbYdhFw21Fwbo+C35HMe36fTE0FBSR4KSfWg= cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= cloud.google.com/go/gsuiteaddons v1.6.7 h1:06Jg3JeLslEfBYX1sDqOPLnF7a3wmhNcDUXF/fVOb50= cloud.google.com/go/gsuiteaddons v1.6.7/go.mod h1:u+sGBvr07OKNnOnQiB/Co1q4U2cjo50ERQwvnlcpNis= cloud.google.com/go/gsuiteaddons v1.6.9 h1:uezUQ2jCcW4jkvB0tbJkMCNVdIa/qGgqnxEqOF8IvwY= cloud.google.com/go/gsuiteaddons v1.6.9/go.mod h1:qITZZoLzQhMQ6Re+izKEvz4C+M1AP13S+XuEpS26824= cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI= cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps= cloud.google.com/go/iap v1.9.4 h1:94zirc2r4t6KzhAMW0R6Dme005eTP6yf7g6vN4IhRrA= cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= cloud.google.com/go/iap v1.9.6 h1:rcuRS9XfOgr1v6TAoihVeSXntOnpVhFlVHtPfgOkLAo= cloud.google.com/go/iap v1.9.6/go.mod h1:YiK+tbhDszhaVifvzt2zTEF2ch9duHtp6xzxj9a0sQk= cloud.google.com/go/iap v1.9.8 h1:oqS5GMxyEDFndqwURKMIaRJ0GXygLJf/2bzue0WkrOU= cloud.google.com/go/iap v1.9.8/go.mod h1:jQzSbtpYRbBoMdOINr/OqUxBY9rhyqLx04utTCmJ6oo= cloud.google.com/go/ids v1.4.5 h1:xd4U7pgl3GHV+MABnv1BF4/Vy/zBF7CYC8XngkOLzag= cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= cloud.google.com/go/ids v1.4.7 h1:wtd+r415yrfZ8LsB6yH6WrOZ26tYt7w6wy3i5a4HQZ8= cloud.google.com/go/ids v1.4.7/go.mod h1:yUkDC71u73lJoTaoONy0dsA0T7foekvg6ZRg9IJL0AA= cloud.google.com/go/ids v1.4.9 h1:JIYwGad3q7kADDAIMw0E/3OR3vtDqjSliRBlWAm+WNk= cloud.google.com/go/ids v1.4.9/go.mod h1:1pL+mhlvtUNphwBSK91yO8NoTVQYwOpqim1anIVBwbM= cloud.google.com/go/iot v1.7.5 h1:munTeBlbqI33iuTYgXy7S8lW2TCgi5l1hA4roSIY+EE= cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= cloud.google.com/go/iot v1.7.7 h1:M9SKIj9eoxoXCzytkLZVAuf5wmoui1OeDqEjC97wRbY= cloud.google.com/go/iot v1.7.7/go.mod h1:tr0bCOSPXtsg64TwwZ/1x+ReTWKlQRVXbM+DnrE54yM= cloud.google.com/go/iot v1.7.9 h1:dsroR14QUU7i2/GC4AcEv1MvKS0VZCYWWTCxxyq2iYo= cloud.google.com/go/iot v1.7.9/go.mod h1:1fi6x4CexbygNgRPn+tcxCjOZFTl+4G6Adbo6sLPR7c= cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= cloud.google.com/go/kms v1.18.2 h1:EGgD0B9k9tOOkbPhYW1PHo2W0teamAUYMOUIcDRMfPk= cloud.google.com/go/kms v1.18.2/go.mod h1:YFz1LYrnGsXARuRePL729oINmN5J/5e7nYijgvfiIeY= cloud.google.com/go/language v1.12.3 h1:iaJZg6K4j/2PvZZVcjeO/btcWWIllVRBhuTFjGO4LXs= cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= cloud.google.com/go/language v1.12.5 h1:kOYJEcuZgyUX/i/4DFrfXPcrddm1XCQD2lDI5hIFmZQ= cloud.google.com/go/language v1.12.5/go.mod h1:w/6a7+Rhg6Bc2Uzw6thRdKKNjnOzfKTJuxzD0JZZ0nM= cloud.google.com/go/language v1.12.7 h1:b8Ilb9pBrXj6aMMD0s8EEp28MSiBMo3FWPHAPNImIy4= cloud.google.com/go/language v1.12.7/go.mod h1:4s/11zABvI/gv+li/+ICe+cErIaN9hYmilf9wrc5Py0= cloud.google.com/go/lifesciences v0.9.5 h1:gXvN70m2p+4zgJFzaz6gMKaxTuF9WJ0USYoMLWAOm8g= cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= cloud.google.com/go/lifesciences v0.9.7 h1:qqEmApr5YFOQjkrU8Jy6o6QpkESqfGbfrE6bnUZZbV8= cloud.google.com/go/lifesciences v0.9.7/go.mod h1:FQ713PhjAOHqUVnuwsCe1KPi9oAdaTfh58h1xPiW13g= cloud.google.com/go/lifesciences v0.9.9 h1:b9AaxLtWOu9IShII4fdLVDOS03CVCsqWX5zXufyRrDU= cloud.google.com/go/lifesciences v0.9.9/go.mod h1:4c8eLVKz7/FPw6lvoHx2/JQX1rVM8+LlYmBp8h5H3MQ= cloud.google.com/go/logging v1.9.0 h1:iEIOXFO9EmSiTjDmfpbRjOxECO7R8C7b8IXUGOj7xZw= cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= cloud.google.com/go/logging v1.10.0 h1:f+ZXMqyrSJ5vZ5pE/zr0xC8y/M9BLNzQeLBwfeZ+wY4= cloud.google.com/go/logging v1.10.0/go.mod h1:EHOwcxlltJrYGqMGfghSet736KR3hX1MAj614mrMk9I= cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= cloud.google.com/go/longrunning v0.5.9 h1:haH9pAuXdPAMqHvzX0zlWQigXT7B0+CL4/2nXXdBo5k= cloud.google.com/go/longrunning v0.5.9/go.mod h1:HD+0l9/OOW0za6UWdKJtXoFAX/BGg/3Wj8p10NeWF7c= cloud.google.com/go/managedidentities v1.6.5 h1:+bpih1piZVLxla/XBqeSUzJBp8gv9plGHIMAI7DLpDM= cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= cloud.google.com/go/managedidentities v1.6.7 h1:uWA9WQyfA0JdkeAFymWUsa3qE9tC33LUElla790Ou1A= cloud.google.com/go/managedidentities v1.6.7/go.mod h1:UzslJgHnc6luoyx2JV19cTCi2Fni/7UtlcLeSYRzTV8= cloud.google.com/go/managedidentities v1.6.9 h1:ktrpu0TWbtLm2wHUUOxXCftD2e8qZvtQZlFLjKyQXUA= cloud.google.com/go/managedidentities v1.6.9/go.mod h1:R7+78iH2j/SCTInutWINxGxEY0PH5rpbWt6uRq0Tn+Y= cloud.google.com/go/maps v1.6.4 h1:EVCZAiDvog9So46460BGbCasPhi613exoaQbpilMVlk= cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= cloud.google.com/go/maps v1.11.0 h1:+//LeUr5ARVau1wVsxLkLnFtYviq9YFS+fB/mhfAOGQ= cloud.google.com/go/maps v1.11.0/go.mod h1:XcSsd8lg4ZhLPCtJ2YHcu/xLVePBzZOlI7GmR2cRCws= cloud.google.com/go/maps v1.11.3 h1:Un4DDZMLfvQT0kAne82lScQib5QJoBg2NDRVJkBokMg= cloud.google.com/go/maps v1.11.3/go.mod h1:4iKNrUzFISQ4RoiWCqIFEAAVtgKb2oQ09AVx8GheOUg= cloud.google.com/go/mediatranslation v0.8.5 h1:c76KdIXljQHSCb/Cy47S8H4s05A4zbK3pAFGzwcczZo= cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= cloud.google.com/go/mediatranslation v0.8.7 h1:izgww3TlyvWyDWdFKnrASpbh12IkAuw8o2ION8sAjX0= cloud.google.com/go/mediatranslation v0.8.7/go.mod h1:6eJbPj1QJwiCP8R4K413qMx6ZHZJUi9QFpApqY88xWU= cloud.google.com/go/mediatranslation v0.8.9 h1:ptRvYRCZPwEk1oHIlSUg7a74czyS7VUP8869PXeaIT8= cloud.google.com/go/mediatranslation v0.8.9/go.mod h1:3MjXTUsEzrMC9My6e9o7TOmgIUGlyrkVAxjzcmxBUdU= cloud.google.com/go/memcache v1.10.5 h1:yeDv5qxRedFosvpMSEswrqUsJM5OdWvssPHFliNFTc4= cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= cloud.google.com/go/memcache v1.10.7 h1:hE7f3ze3+eWh/EbYXEz7oXkm0LXcr7UCoLklwi7gsLU= cloud.google.com/go/memcache v1.10.7/go.mod h1:SrU6+QBhvXJV0TA59+B3oCHtLkPx37eqdKmRUlmSE1k= cloud.google.com/go/memcache v1.10.9 h1:Wks0hJCdprJkYn0kYTW5oto3NodsGqn98Urvj3fJgX4= cloud.google.com/go/memcache v1.10.9/go.mod h1:06evGxt9E1Mf/tYsXJNdXuRj5qzspVd0Tt18kXYDD5c= cloud.google.com/go/metastore v1.13.4 h1:dR7vqWXlK6IYR8Wbu9mdFfwlVjodIBhd1JRrpZftTEg= cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= cloud.google.com/go/metastore v1.13.6 h1:otHcJkci5f/sNRedrSM7eM81QRnu0yZ3HvkvWGphABA= cloud.google.com/go/metastore v1.13.6/go.mod h1:OBCVMCP7X9vA4KKD+5J4Q3d+tiyKxalQZnksQMq5MKY= cloud.google.com/go/metastore v1.13.8 h1:aGLOZ6tPsGveXVST2c6tf2mjFm5bEcBij8qh4qInz+I= cloud.google.com/go/metastore v1.13.8/go.mod h1:2uLJBAXn5EDYJx9r7mZtxZifCKpakZUCvNfzI7ejUiE= cloud.google.com/go/monitoring v1.18.0 h1:NfkDLQDG2UR3WYZVQE8kwSbUIEyIqJUPl+aOQdFH1T4= cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= cloud.google.com/go/monitoring v1.19.0 h1:NCXf8hfQi+Kmr56QJezXRZ6GPb80ZI7El1XztyUuLQI= cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw= cloud.google.com/go/monitoring v1.20.1 h1:XmM6uk4+mI2ZhWdI2n/2GNhJdpeQN+1VdG2UWEDhX48= cloud.google.com/go/monitoring v1.20.1/go.mod h1:FYSe/brgfuaXiEzOQFhTjsEsJv+WePyK71X7Y8qo6uQ= cloud.google.com/go/networkconnectivity v1.14.4 h1:GBfXFhLyPspnaBE3nI/BRjdhW8vcbpT9QjE/4kDCDdc= cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= cloud.google.com/go/networkconnectivity v1.14.6 h1:jYpQ86mZ7OYZc7WadvCIlIaPXmXhr5nD7wgE/ekMVpM= cloud.google.com/go/networkconnectivity v1.14.6/go.mod h1:/azB7+oCSmyBs74Z26EogZ2N3UcXxdCHkCPcz8G32bU= cloud.google.com/go/networkconnectivity v1.14.8 h1:PSOYigOrl3pTFfRBPQk5uRlxSxn0G1HY7FNZPGz5Quw= cloud.google.com/go/networkconnectivity v1.14.8/go.mod h1:QQ/XTMk7U5fzv1cVNUCQJEjpkVEE+nYOK7mg3hVTuiI= cloud.google.com/go/networkmanagement v1.9.4 h1:aLV5GcosBNmd6M8+a0ekB0XlLRexv4fvnJJrYnqeBcg= cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= cloud.google.com/go/networkmanagement v1.13.2 h1:Ex1/aYkA0areleSmOGXHvEFBGohteIYJr2SGPrjOUe0= cloud.google.com/go/networkmanagement v1.13.2/go.mod h1:24VrV/5HFIOXMEtVQEUoB4m/w8UWvUPAYjfnYZcBc4c= cloud.google.com/go/networkmanagement v1.13.4 h1:CUX6YYtC6DpV0BzsaovqWExieVPDxmUxvQVlEjf0mwQ= cloud.google.com/go/networkmanagement v1.13.4/go.mod h1:dGTeJfDPQv0yGDt6gncj4XAPwxktjpCn5ZxQajStW8g= cloud.google.com/go/networksecurity v0.9.5 h1:+caSxBTj0E8OYVh/5wElFdjEMO1S/rZtE1152Cepchc= cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= cloud.google.com/go/networksecurity v0.9.7 h1:aepEkfiwOvUL9eu3ginVZhTaXDRHncQKi9lTT1BycH0= cloud.google.com/go/networksecurity v0.9.7/go.mod h1:aB6UiPnh/l32+TRvgTeOxVRVAHAFFqvK+ll3idU5BoY= cloud.google.com/go/networksecurity v0.9.9 h1:DDqzpqx1u1vDiYW2bBr0r3A5kIw3D5f4RtQkWiRd7Jg= cloud.google.com/go/networksecurity v0.9.9/go.mod h1:aLS+6sLeZkMhLx9ntTMJG4qWHdvDPctqMOb6ggz9m5s= cloud.google.com/go/notebooks v1.11.3 h1:FH48boYmrWVQ6k0Mx/WrnNafXncT5iSYxA8CNyWTgy0= cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= cloud.google.com/go/notebooks v1.11.5 h1:sFU1ETg1HfIN/Tev8gD0dleAITLv7cHp0JClwFmJ6bo= cloud.google.com/go/notebooks v1.11.5/go.mod h1:pz6P8l2TvhWqAW3sysIsS0g2IUJKOzEklsjWJfi8sd4= cloud.google.com/go/notebooks v1.11.7 h1:/SeTEbFaU3cwzvc0ycM3nJ+8DvSTS8oeOWKi0bzEItM= cloud.google.com/go/notebooks v1.11.7/go.mod h1:lTjloYceMboZanBFC/JSZYet/K+JuO0mLAXVVhb/6bQ= cloud.google.com/go/optimization v1.6.3 h1:63NZaWyN+5rZEKHPX4ACpw3BjgyeuY8+rCehiCMaGPY= cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= cloud.google.com/go/optimization v1.6.5 h1:FPfowA/LEckKTQT0A4NJMI2bSou999c2ZyFX1zGiYxY= cloud.google.com/go/optimization v1.6.5/go.mod h1:eiJjNge1NqqLYyY75AtIGeQWKO0cvzD1ct/moCFaP2Q= cloud.google.com/go/optimization v1.6.7 h1:HFaCNq1upokZP4cPelqszhUShkmIypWma5IGe4fh4CA= cloud.google.com/go/optimization v1.6.7/go.mod h1:FREForRqqjTsJbElYyWSgb54WXUzTMTRyjVT+Tl80v8= cloud.google.com/go/orchestration v1.8.5 h1:YHgWMlrPttIVGItgGfuvO2KM7x+y9ivN/Yk92pMm1a4= cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= cloud.google.com/go/orchestration v1.9.2 h1:C2WL4ZnclXsh4XickGhKYKlPjqVZj35y1sbRjdsZ3g4= cloud.google.com/go/orchestration v1.9.2/go.mod h1:8bGNigqCQb/O1kK7PeStSNlyi58rQvZqDiuXT9KAcbg= cloud.google.com/go/orchestration v1.9.4 h1:xwqKYWlnDMLETKpZmPg+edCehC7w4G11d/8JSqutC5I= cloud.google.com/go/orchestration v1.9.4/go.mod h1:jk5hczI8Tciq+WCkN32GpjWJs67GSmAA0XHFUlELJLw= cloud.google.com/go/orgpolicy v1.12.1 h1:2JbXigqBJVp8Dx5dONUttFqewu4fP0p3pgOdIZAhpYU= cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= cloud.google.com/go/orgpolicy v1.12.3 h1:fGftW2bPi8vTjQm57xlwtLBZQcrgC+c3HMFBzJ+KWPc= cloud.google.com/go/orgpolicy v1.12.3/go.mod h1:6BOgIgFjWfJzTsVcib/4QNHOAeOjCdaBj69aJVs//MA= cloud.google.com/go/orgpolicy v1.12.5 h1:NEbK9U6HuhjXOUI1+fJVdIEh0FHiJtGVq4kYQQ5B8t8= cloud.google.com/go/orgpolicy v1.12.5/go.mod h1:f778/jOHKp6cP6NbbQgjy4SDfQf6BoVGiSWdxky3ONQ= cloud.google.com/go/osconfig v1.12.5 h1:Mo5jGAxOMKH/PmDY7fgY19yFcVbvwREb5D5zMPQjFfo= cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= cloud.google.com/go/osconfig v1.12.7 h1:HXsXGFaFaLTklwKgSob/GSE+c3verYDQDgreFaosxyc= cloud.google.com/go/osconfig v1.12.7/go.mod h1:ID7Lbqr0fiihKMwAOoPomWRqsZYKWxfiuafNZ9j1Y1M= cloud.google.com/go/osconfig v1.13.0 h1:k+nAmaTcJ08BSR1yGadRZyLwRSvk5XgaZJinS1sEz4Q= cloud.google.com/go/osconfig v1.13.0/go.mod h1:tlACnQi1rtSLnHRYzfw9SH9zXs0M7S1jqiW2EOCn2Y0= cloud.google.com/go/oslogin v1.13.1 h1:1K4nOT5VEZNt7XkhaTXupBYos5HjzvJMfhvyD2wWdFs= cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= cloud.google.com/go/oslogin v1.13.3 h1:7AgOWH1oMPrB1AVU0/f47ADdOt+XfdBY7QRb8tcMUp8= cloud.google.com/go/oslogin v1.13.3/go.mod h1:WW7Rs1OJQ1iSUckZDilvNBSNPE8on740zF+4ZDR4o8U= cloud.google.com/go/oslogin v1.13.5 h1:IptgM0b9yNJzEbC5rEetbRAcxsuRXDMuSX/65qASvE8= cloud.google.com/go/oslogin v1.13.5/go.mod h1:V+QzBAbZBZJq9CmTyzKrh3rpMiWIr1OBn6RL4mMVWXI= cloud.google.com/go/phishingprotection v0.8.5 h1:DH3WFLzEoJdW/6xgsmoDqOwT1xddFi7gKu0QGZQhpGU= cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= cloud.google.com/go/phishingprotection v0.8.7 h1:CbCjfR/pgDHyRMu94o9nuGwaONEcarWnUfSGGw+I2ZI= cloud.google.com/go/phishingprotection v0.8.7/go.mod h1:FtYaOyGc/HQQU7wY4sfwYZBFDKAL+YtVBjUj8E3A3/I= cloud.google.com/go/phishingprotection v0.8.9 h1:Gg3XeqWW0g97MKvexeMytrxu31UHDjUd0bbzHa40D8o= cloud.google.com/go/phishingprotection v0.8.9/go.mod h1:xNojFKIdq+hNGNpOZOEGVGA4Mdhm2yByMli2Ni/RV0w= cloud.google.com/go/policytroubleshooter v1.10.3 h1:c0WOzC6hz964QWNBkyKfna8A2jOIx1zzZa43Gx/P09o= cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= cloud.google.com/go/policytroubleshooter v1.10.5 h1:LGt85MZUKlq9oqsbBL9+M6jAyeuR1TtCx6k5HfAQxTY= cloud.google.com/go/policytroubleshooter v1.10.5/go.mod h1:bpOf94YxjWUqsVKokzPBibMSAx937Jp2UNGVoMAtGYI= cloud.google.com/go/policytroubleshooter v1.10.7 h1:A3KZBrc2Qzq5jQI8M8hW4GscOBZzIvoOhwRiE41pqcY= cloud.google.com/go/policytroubleshooter v1.10.7/go.mod h1:/JxxZOSCT8nASvH/SP4Bj81EnDFwZhFThG7mgVWIoPY= cloud.google.com/go/privatecatalog v0.9.5 h1:UZ0assTnATXSggoxUIh61RjTQ4P9zCMk/kEMbn0nMYA= cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= cloud.google.com/go/privatecatalog v0.9.7 h1:wGZKKJhYyuf4gcAEywQqQ6F19yxhBJGnzgyxOTbJjBw= cloud.google.com/go/privatecatalog v0.9.7/go.mod h1:NWLa8MCL6NkRSt8jhL8Goy2A/oHkvkeAxiA0gv0rIXI= cloud.google.com/go/privatecatalog v0.9.9 h1:fV9+FuZuN6pup4h3qh/0HGpssJrkI5EyZVLQEEvzrA4= cloud.google.com/go/privatecatalog v0.9.9/go.mod h1:attFfOEf8ECrCuCdT3WYY8wyMKRZt4iB1bEWYFzPn50= cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= cloud.google.com/go/pubsub v1.38.0 h1:J1OT7h51ifATIedjqk/uBNPh+1hkvUaH4VKbz4UuAsc= cloud.google.com/go/pubsub v1.38.0/go.mod h1:IPMJSWSus/cu57UyR01Jqa/bNOQA+XnPF6Z4dKW4fAA= cloud.google.com/go/pubsub v1.40.0 h1:0LdP+zj5XaPAGtWr2V6r88VXJlmtaB/+fde1q3TU8M0= cloud.google.com/go/pubsub v1.40.0/go.mod h1:BVJI4sI2FyXp36KFKvFwcfDRDfR8MiLT8mMhmIhdAeA= cloud.google.com/go/pubsublite v1.8.1 h1:pX+idpWMIH30/K7c0epN6V703xpIcMXWRjKJsz0tYGY= cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise/v2 v2.9.2 h1:U3Wfq12X9cVMuTpsWDSURnXF0Z9hSPTHj+xsnXDRLsw= cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0 h1:+QG02kE63W13vXI+rwAxFF3EhGX6K7gXwFz9OKwKcHw= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0/go.mod h1:jNYyn2ScR4DTg+VNhjhv/vJQdaU8qz+NpmpIzEE7HFQ= cloud.google.com/go/recaptchaenterprise/v2 v2.14.0 h1:revhoyewcQrpKccogfKNO2ul3aQbD11BU+ZsRpOWlgw= cloud.google.com/go/recaptchaenterprise/v2 v2.14.0/go.mod h1:pwC/eCyXq37YV3NSaiJsfOmuoTDkzURnVKAWGSkjDUY= cloud.google.com/go/recommendationengine v0.8.5 h1:ineqLswaCSBY0csYv5/wuXJMBlxATK6Xc5jJkpiTEdM= cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= cloud.google.com/go/recommendationengine v0.8.7 h1:N6n/TEr0FQzeP4ZtvF5daMszOhdZI94uMiPiAi9kFMo= cloud.google.com/go/recommendationengine v0.8.7/go.mod h1:YsUIbweUcpm46OzpVEsV5/z+kjuV6GzMxl7OAKIGgKE= cloud.google.com/go/recommendationengine v0.8.9 h1:jewIoRtf1F4WgtIDdPEKDqpvPU+utN02sFw3iYbmvwM= cloud.google.com/go/recommendationengine v0.8.9/go.mod h1:QgE5f6s20QhCXf4UR9KMI/Q6Spykd2zEYXX2oBz6Cbs= cloud.google.com/go/recommender v1.12.1 h1:LVLYS3r3u0MSCxQSDUtLSkporEGi9OAE6hGvayrZNPs= cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= cloud.google.com/go/recommender v1.12.3 h1:v9x75vXP5wMXw3QG3xmgjVHLlqYufuLn/ht3oNWCA3w= cloud.google.com/go/recommender v1.12.3/go.mod h1:OgN0MjV7/6FZUUPgF2QPQtYErtZdZc4u+5onvurcGEI= cloud.google.com/go/recommender v1.12.5 h1:91NMrObmes2zA+gI0+QhCFH1oTPHlMGFTAJy5MTD2eg= cloud.google.com/go/recommender v1.12.5/go.mod h1:ggh5JNuG5ajpRqqcEkgni/DjpS7x12ktO+Edu8bmCJM= cloud.google.com/go/redis v1.14.2 h1:QF0maEdVv0Fj/2roU8sX3NpiDBzP9ICYTO+5F32gQNo= cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= cloud.google.com/go/redis v1.16.0 h1:1veL/h/x5bgzG2CLK2cdG3plWdgO0p1qoHgwFBqG7+c= cloud.google.com/go/redis v1.16.0/go.mod h1:NLzG3Ur8ykVIZk+i5ienRnycsvWzQ0uCLcil6Htc544= cloud.google.com/go/redis v1.16.2 h1:QbarPMu22tuUOqi3ynNKk2mQWl7xitMTxAaAUaBUFsE= cloud.google.com/go/redis v1.16.2/go.mod h1:bn/4nXSZkoH4QTXRjqWR2AZ0WA1b13ct354nul2SSiU= cloud.google.com/go/resourcemanager v1.9.5 h1:AZWr1vWVDKGwfLsVhcN+vcwOz3xqqYxtmMa0aABCMms= cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= cloud.google.com/go/resourcemanager v1.9.7 h1:SdvD0PaPX60+yeKoSe16mawFpM0EPuiPPihTIVlhRsY= cloud.google.com/go/resourcemanager v1.9.7/go.mod h1:cQH6lJwESufxEu6KepsoNAsjrUtYYNXRwxm4QFE5g8A= cloud.google.com/go/resourcemanager v1.9.9 h1:9JgRo4uBdCLJpWb6c+1+q7QPyWzH0LSCKUcF/IliKNk= cloud.google.com/go/resourcemanager v1.9.9/go.mod h1:vCBRKurJv+XVvRZ0XFhI/eBrBM7uBOPFjMEwSDMIflY= cloud.google.com/go/resourcesettings v1.6.5 h1:BTr5MVykJwClASci/7Og4Qfx70aQ4n3epsNLj94ZYgw= cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= cloud.google.com/go/resourcesettings v1.7.0 h1:yEuByg5XBHhTG9wPEU7GiEtC9Orp1wSEyiiX4IPqoSY= cloud.google.com/go/resourcesettings v1.7.0/go.mod h1:pFzZYOQMyf1hco9pbNWGEms6N/2E7nwh0oVU1Tz+4qA= cloud.google.com/go/resourcesettings v1.7.2 h1:Q3udMNHhYLrzVNrCYEpZ6f70Rf6nHpiPFay1ILwcQ80= cloud.google.com/go/resourcesettings v1.7.2/go.mod h1:mNdB5Wl9/oVr9Da3OrEstSyXCT949ignvO6ZrmYdmGU= cloud.google.com/go/retail v1.16.0 h1:Fn1GuAua1c6crCGqfJ1qMxG1Xh10Tg/x5EUODEHMqkw= cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= cloud.google.com/go/retail v1.16.2 h1:msP5a8BOxVym2DvoubeWAxAeV6VhYkKnYHc2XOkd/+U= cloud.google.com/go/retail v1.16.2/go.mod h1:T7UcBh4/eoxRBpP3vwZCoa+PYA9/qWRTmOCsV8DRdZ0= cloud.google.com/go/retail v1.17.2 h1:RovE7VK3TEFDECBXwVWItL21+QQ4WY6otLCZHqExMBQ= cloud.google.com/go/retail v1.17.2/go.mod h1:Ad6D8tkDZatI1X7szhhYWiatZmH6nSUfZ3WeCECyA0E= cloud.google.com/go/run v1.3.4 h1:m9WDA7DzTpczhZggwYlZcBWgCRb+kgSIisWn1sbw2rQ= cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= cloud.google.com/go/run v1.3.7 h1:E4Z5e681Qh7UJrJRMCgYhp+3tkcoXiaKGh3UZmUPaAQ= cloud.google.com/go/run v1.3.7/go.mod h1:iEUflDx4Js+wK0NzF5o7hE9Dj7QqJKnRj0/b6rhVq20= cloud.google.com/go/run v1.3.9 h1:De6XlIBjzEFXPzDQ/hJgvieh4H/105mhkkwxL5DmH0o= cloud.google.com/go/run v1.3.9/go.mod h1:Ep/xsiUt5ZOwNptGl1FBlHb+asAgqB+9RDJKBa/c1mI= cloud.google.com/go/scheduler v1.10.6 h1:5U8iXLoQ03qOB+ZXlAecU7fiE33+u3QiM9nh4cd0eTE= cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= cloud.google.com/go/scheduler v1.10.8 h1:Jn/unfNUgRiNJRc1nrApzimKiVj91UYlLT8mMfpUu48= cloud.google.com/go/scheduler v1.10.8/go.mod h1:0YXHjROF1f5qTMvGTm4o7GH1PGAcmu/H/7J7cHOiHl0= cloud.google.com/go/scheduler v1.10.10 h1:KYdENFZip7O2Jk/zuNzEPIv+ZQokkWnNZ5AnrIuooYo= cloud.google.com/go/scheduler v1.10.10/go.mod h1:nOLkchaee8EY0g73hpv613pfnrZwn/dU2URYjJbRLR0= cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/secretmanager v1.13.1 h1:TTGo2Vz7ZxYn2QbmuFP7Zo4lDm5VsbzBjDReo3SA5h4= cloud.google.com/go/secretmanager v1.13.1/go.mod h1:y9Ioh7EHp1aqEKGYXk3BOC+vkhlHm9ujL7bURT4oI/4= cloud.google.com/go/secretmanager v1.13.3 h1:VqUVYY3U6uFXOhPdZgAoZH9m8E6p7eK02TsDRj2SBf4= cloud.google.com/go/secretmanager v1.13.3/go.mod h1:e45+CxK0w6GaL4hS+KabgQskl4RdSS30b+HRf0TH0kk= cloud.google.com/go/security v1.15.5 h1:wTKJQ10j8EYgvE8Y+KhovxDRVDk2iv/OsxZ6GrLP3kE= cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= cloud.google.com/go/security v1.17.0 h1:u4RCnEQPvlrrnFRFinU0T3WsjtrsQErkWBfqTM5oUQI= cloud.google.com/go/security v1.17.0/go.mod h1:eSuFs0SlBv1gWg7gHIoF0hYOvcSwJCek/GFXtgO6aA0= cloud.google.com/go/security v1.17.2 h1:pEkUeR1PFNwoFAIXPMa4PBCYb75UT8LmNfjQy1fm/Co= cloud.google.com/go/security v1.17.2/go.mod h1:6eqX/AgDw56KwguEBfFNiNQ+Vzi+V6+GopklexYuJ0U= cloud.google.com/go/securitycenter v1.24.4 h1:/5jjkZ+uGe8hZ7pvd7pO30VW/a+pT2MrrdgOqjyucKQ= cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= cloud.google.com/go/securitycenter v1.30.0 h1:Y8C0I/mzLbaxAl5cw3EaLox0Rvpy+VUwEuCGWIQDMU8= cloud.google.com/go/securitycenter v1.30.0/go.mod h1:/tmosjS/dfTnzJxOzZhTXdX3MXWsCmPWfcYOgkJmaJk= cloud.google.com/go/securitycenter v1.32.0 h1:UJvalA9NoLhU0DWLa10qMSvMucEe+iQOqxC4/KGqMys= cloud.google.com/go/securitycenter v1.32.0/go.mod h1:s1dN6hM6HZyzUyJrqBoGvhxR/GecT5u48sidMIgDxTo= cloud.google.com/go/servicedirectory v1.11.4 h1:da7HFI1229kyzIyuVEzHXip0cw0d+E0s8mjQby0WN+k= cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= cloud.google.com/go/servicedirectory v1.11.7 h1:c3OAhTcZ8LbIiKps5T3p6i0QcPI8/aWYwOfoZobICKo= cloud.google.com/go/servicedirectory v1.11.7/go.mod h1:fiO/tM0jBpVhpCAe7Yp5HmEsmxSUcOoc4vPrO02v68I= cloud.google.com/go/servicedirectory v1.11.9 h1:KivmF5S9i6av+7tgkHgcosC51jEtmC9UvgayezP2Uqo= cloud.google.com/go/servicedirectory v1.11.9/go.mod h1:qiDNuIS2qxuuroSmPNuXWxoFMvsEudKXP62Wos24BsU= cloud.google.com/go/shell v1.7.5 h1:3Fq2hzO0ZSyaqBboJrFkwwf/qMufDtqwwA6ep8EZxEI= cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= cloud.google.com/go/shell v1.7.7 h1:HxCzcUxSsCh6FJWkmbOUrGI1sKe4E1Yy4vaykn4RhJ4= cloud.google.com/go/shell v1.7.7/go.mod h1:7OYaMm3TFMSZBh8+QYw6Qef+fdklp7CjjpxYAoJpZbQ= cloud.google.com/go/shell v1.7.9 h1:CPn8dHSJgZsIaMtGw5iMoF/6Ab7l5A2g34CIjVxlU3c= cloud.google.com/go/shell v1.7.9/go.mod h1:h3wVC6qaQ1nIlSWMasl1e/uwmepVbZpjSk/Bn7ZafSc= cloud.google.com/go/spanner v1.56.0 h1:o/Cv7/zZ1WgRXVCd5g3Nc23ZI39p/1pWFqFwvg6Wcu8= cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= cloud.google.com/go/spanner v1.63.0 h1:P6+BY70Wtol4MtryBgnXZVTZfsdySEvWfz0EpyLwHi4= cloud.google.com/go/spanner v1.63.0/go.mod h1:iqDx7urZpgD7RekZ+CFvBRH6kVTW1ZSEb2HMDKOp5Cc= cloud.google.com/go/spanner v1.64.0 h1:ltyPbHA/nRAtAhU/o742dXBCI1eNHPeaRY09Ja8B+hM= cloud.google.com/go/spanner v1.64.0/go.mod h1:TOFx3pb2UwPsDGlE1gTehW+y6YlU4IFk+VdDHSGQS/M= cloud.google.com/go/speech v1.21.1 h1:nuFc+Kj5B8de75nN4FdPyUbI2SiBoHZG6BLurXL56Q0= cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= cloud.google.com/go/speech v1.23.1 h1:TcWEAOLQH1Lb2fhHS6/GjvAh+ue0dt4xUDHXHG6vF04= cloud.google.com/go/speech v1.23.1/go.mod h1:UNgzNxhNBuo/OxpF1rMhA/U2rdai7ILL6PBXFs70wq0= cloud.google.com/go/speech v1.23.3 h1:zuiX3ExV9jv1rrTFFyYZF5DvYys0/JByeErC50Hyw+g= cloud.google.com/go/speech v1.23.3/go.mod h1:u7tK/jxhzRZwZ5Nujhau7iLI3+VfJKYhpoZTjU7hRsE= cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k= cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= cloud.google.com/go/storage v1.41.0 h1:RusiwatSu6lHeEXe3kglxakAmAbfV+rhtPqA6i8RBx0= cloud.google.com/go/storage v1.41.0/go.mod h1:J1WCa/Z2FcgdEDuPUY8DxT5I+d9mFKsCepp5vR6Sq80= cloud.google.com/go/storagetransfer v1.10.4 h1:dy4fL3wO0VABvzM05ycMUPFHxTPbJz9Em8ikAJVqSbI= cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= cloud.google.com/go/storagetransfer v1.10.6 h1:CXmoNEvz7y2NtHFZuH3Z8ASN43rxRINWa2Q/IlBzM2k= cloud.google.com/go/storagetransfer v1.10.6/go.mod h1:3sAgY1bx1TpIzfSzdvNGHrGYldeCTyGI/Rzk6Lc6A7w= cloud.google.com/go/storagetransfer v1.10.8 h1:hFCYNbls3DoAA49BZ8bWfmdUPfwLa708h1F6gPy76OE= cloud.google.com/go/storagetransfer v1.10.8/go.mod h1:fEGWYffkV9OYOKms8nxyJWIZA7iEWPl2Mybk6bpQnEk= cloud.google.com/go/talent v1.6.6 h1:JssV0CE3FNujuSWn7SkosOzg7qrMxVnt6txOfGcMSa4= cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= cloud.google.com/go/talent v1.6.8 h1:RoyEtftfJrbwJcu63zuWE4IjC76xMyVsJBhmleIp3bE= cloud.google.com/go/talent v1.6.8/go.mod h1:kqPAJvhxmhoUTuqxjjk2KqA8zUEeTDmH+qKztVubGlQ= cloud.google.com/go/talent v1.6.10 h1:Zc1FO2NTLjCNztqnyll7DwKobFYomyCijRlqbJj+7mc= cloud.google.com/go/talent v1.6.10/go.mod h1:q2/qIb2Eb2svmeBfkCGIia/NGmkcScdyYSyNNOgFRLI= cloud.google.com/go/texttospeech v1.7.5 h1:dxY2Q5mHCbrGa3oPR2O3PCicdnvKa1JmwGQK36EFLOw= cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= cloud.google.com/go/texttospeech v1.7.7 h1:qR6Mu+EM2OfaZR1/Rl8BDBTVfi2X5OtwKKvJRSQyG+o= cloud.google.com/go/texttospeech v1.7.7/go.mod h1:XO4Wr2VzWHjzQpMe3gS58Oj68nmtXMyuuH+4t0wy9eA= cloud.google.com/go/texttospeech v1.7.9 h1:wn9UNRlEw+vCDFd2NBVPrNGFwB+n/cV20i81MBlbwas= cloud.google.com/go/texttospeech v1.7.9/go.mod h1:nuo7l7CVWUMvaTgswbn/hhn2Tv73/WbenqGyc236xpo= cloud.google.com/go/tpu v1.6.5 h1:C8YyYda8WtNdBoCgFwwBzZd+S6+EScHOxM/z1h0NNp8= cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= cloud.google.com/go/tpu v1.6.7 h1:ngQokxUB1z2gvHn3vAf04m7SFnNYMiQIIpny81fCGAs= cloud.google.com/go/tpu v1.6.7/go.mod h1:o8qxg7/Jgt7TCgZc3jNkd4kTsDwuYD3c4JTMqXZ36hU= cloud.google.com/go/tpu v1.6.9 h1:e6TbpIGmKdFFjW/OH8uQl0U0+t0K4TVN5mO2C+zBBtQ= cloud.google.com/go/tpu v1.6.9/go.mod h1:6C7Ed7Le5Y1vWGR+8lQWsh/gmqK6l53lgji0YXBU40o= cloud.google.com/go/trace v1.10.5 h1:0pr4lIKJ5XZFYD9GtxXEWr0KkVeigc3wlGpZco0X1oA= cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= cloud.google.com/go/trace v1.10.7 h1:gK8z2BIJQ3KIYGddw9RJLne5Fx0FEXkrEQzPaeEYVvk= cloud.google.com/go/trace v1.10.7/go.mod h1:qk3eiKmZX0ar2dzIJN/3QhY2PIFh1eqcIdaN5uEjQPM= cloud.google.com/go/trace v1.10.9 h1:Cy6D1Zdz8up4mIPUWModTuIGDr3fh7AZaCnR+uyxpgA= cloud.google.com/go/trace v1.10.9/go.mod h1:vtWRnvEh+d8h2xljwxVwsdxxpoWZkxcNYnJF3FuJUV8= cloud.google.com/go/translate v1.10.1 h1:upovZ0wRMdzZvXnu+RPam41B0mRJ+coRXFP2cYFJ7ew= cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= cloud.google.com/go/translate v1.10.3 h1:g+B29z4gtRGsiKDoTF+bNeH25bLRokAaElygX2FcZkE= cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/translate v1.10.5 h1:HGFw8dhEp6xYCDWG5fRNwZHfY6MiyCh97RHBBkzsuNM= cloud.google.com/go/translate v1.10.5/go.mod h1:n9fFca4U/EKr2GzJKrnQXemlYhfo1mT1nSt7Rt4l/VA= cloud.google.com/go/video v1.20.4 h1:TXwotxkShP1OqgKsbd+b8N5hrIHavSyLGvYnLGCZ7xc= cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= cloud.google.com/go/video v1.21.0 h1:ue/1C8TF8H2TMzKMBdNnFxT7QaeWMtqfDr9TSQGgUhA= cloud.google.com/go/video v1.21.0/go.mod h1:Kqh97xHXZ/bIClgDHf5zkKvU3cvYnLyRefmC8yCBqKI= cloud.google.com/go/video v1.21.2 h1:f/Ez6k2aeN+1+XoAaFCTTqOD+oq8c38fHDi8vd9D3tg= cloud.google.com/go/video v1.21.2/go.mod h1:UNXGQj3Hdyb70uaF9JeeM8Y8BAmAzLEMSWmyBKY2iVM= cloud.google.com/go/videointelligence v1.11.5 h1:mYaWH8uhUCXLJCN3gdXswKzRa2+lK0zN6/KsIubm6pE= cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= cloud.google.com/go/videointelligence v1.11.7 h1:SKBkFTuOclESLjQL1LwraqVFm2fL5oL9tbzKITU+FOY= cloud.google.com/go/videointelligence v1.11.7/go.mod h1:iMCXbfjurmBVgKuyLedTzv90kcnppOJ6ttb0+rLDID0= cloud.google.com/go/videointelligence v1.11.9 h1:fGlVXtrk3mIh2DFIggTQ4xoA2VruiTkXZHCl6IDY0Bk= cloud.google.com/go/videointelligence v1.11.9/go.mod h1:Mv0dgb6U12BfBRPj39nM/7gcAFS1+VVGpTiyMJ/ShPo= cloud.google.com/go/vision/v2 v2.8.0 h1:W52z1b6LdGI66MVhE70g/NFty9zCYYcjdKuycqmlhtg= cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= cloud.google.com/go/vision/v2 v2.8.2 h1:j9RxG8DcyJO/D7/ps2pOey8VZys+TMqF79bWAhuM7QU= cloud.google.com/go/vision/v2 v2.8.2/go.mod h1:BHZA1LC7dcHjSr9U9OVhxMtLKd5l2jKPzLRALEJvuaw= cloud.google.com/go/vision/v2 v2.8.4 h1:kBZ62LquS8V8u+N8wWTLgn2tHqaC4poQuGjRaaR+WGE= cloud.google.com/go/vision/v2 v2.8.4/go.mod h1:qlmeVbmCfPNuD1Kwa7/evqCJYoJ7WhiZ2XeVSYwiOaA= cloud.google.com/go/vmmigration v1.7.5 h1:5v9RT2vWyuw3pK2ox0HQpkoftO7Q7/8591dTxxQc79g= cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= cloud.google.com/go/vmmigration v1.7.7 h1:bf2qKqEN7iqT62IptQ/FDadoDLJI9sthyrW3PVaH8bY= cloud.google.com/go/vmmigration v1.7.7/go.mod h1:qYIK5caZY3IDMXQK+A09dy81QU8qBW0/JDTc39OaKRw= cloud.google.com/go/vmmigration v1.7.9 h1:+X5Frseyehz8ZvnVSRZYXAwEEQXjS4oKK4EV/0KbS9s= cloud.google.com/go/vmmigration v1.7.9/go.mod h1:x5LQyAESUXsI7/QAQY6BV8xEjIrlkGI+S+oau/Sb0Gs= cloud.google.com/go/vmwareengine v1.1.1 h1:EGdDi9QbqThfZq3ILcDK5g+m9jTevc34AY5tACx5v7k= cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= cloud.google.com/go/vmwareengine v1.1.3 h1:x4KwHB4JlBEzMaITVhrbbpHrU+2I5LrlvHGEEluT0vc= cloud.google.com/go/vmwareengine v1.1.3/go.mod h1:UoyF6LTdrIJRvDN8uUB8d0yimP5A5Ehkr1SRzL1APZw= cloud.google.com/go/vmwareengine v1.1.5 h1:tzqTbh5CAqZDVJrEgbRGDFgPyCx5bjIPH5Cm0xqVamA= cloud.google.com/go/vmwareengine v1.1.5/go.mod h1:Js6QbSeC1OgpyygalCrMj90wa93O3kFgcs/u1YzCKsU= cloud.google.com/go/vpcaccess v1.7.5 h1:XyL6hTLtEM/eE4F1GEge8xUN9ZCkiVWn44K/YA7z1rQ= cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= cloud.google.com/go/vpcaccess v1.7.7 h1:F5woMLufKnshmDvPVxCzoC+Di12RYXQ1W8kNmpBT8z0= cloud.google.com/go/vpcaccess v1.7.7/go.mod h1:EzfSlgkoAnFWEMznZW0dVNvdjFjEW97vFlKk4VNBhwY= cloud.google.com/go/vpcaccess v1.7.9 h1:LbQaXRQMTPCPmJKoVIW/2vvj80FCiGG+lAyOzNpKs6M= cloud.google.com/go/vpcaccess v1.7.9/go.mod h1:Y0BlcnG9yTkoM6IL6auBeKvVEXL4LmNIxzscekrn/uk= cloud.google.com/go/webrisk v1.9.5 h1:251MvGuC8wisNN7+jqu9DDDZAi38KiMXxOpA/EWy4dE= cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= cloud.google.com/go/webrisk v1.9.7 h1:EWTSVagWWeQjVAsebiF/wJMwC5bq6Zz3LqOmD9Uid4s= cloud.google.com/go/webrisk v1.9.7/go.mod h1:7FkQtqcKLeNwXCdhthdXHIQNcFWPF/OubrlyRcLHNuQ= cloud.google.com/go/webrisk v1.9.9 h1:WmSWTAIpQEKscbnbVUeWWdq+p11Q8P1Gn6ADI8yAQCI= cloud.google.com/go/webrisk v1.9.9/go.mod h1:Wre67XdNQbt0LCBrvwVNBS5ORb8ssixq/u04CCZoO+k= cloud.google.com/go/websecurityscanner v1.6.5 h1:YqWZrZYabG88TZt7364XWRJGhxmxhony2ZUyZEYMF2k= cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= cloud.google.com/go/websecurityscanner v1.6.7 h1:R5OW5SNRqD0DSEmyWLUMNYAXWYnz/NLSXBawVFrc9a0= cloud.google.com/go/websecurityscanner v1.6.7/go.mod h1:EpiW84G5KXxsjtFKK7fSMQNt8JcuLA8tQp7j0cyV458= cloud.google.com/go/websecurityscanner v1.6.9 h1:4tbX6llT8kBqUJbpB4Wjj9sqWNYwCUGt3WP6uVVv00w= cloud.google.com/go/websecurityscanner v1.6.9/go.mod h1:xrMxPiHB5iFxvc2tqbfUr6inPox6q6y7Wg0LTyZOKTw= cloud.google.com/go/workflows v1.12.4 h1:uHNmUiatTbPQ4H1pabwfzpfEYD4BBnqDHqMm2IesOh4= cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= cloud.google.com/go/workflows v1.12.6 h1:2bE69mh68law1UZWPjgmvOQsjsGSppRudABAXwNAy58= cloud.google.com/go/workflows v1.12.6/go.mod h1:oDbEHKa4otYg4abwdw2Z094jB0TLLiFGAPA78EDAKag= cloud.google.com/go/workflows v1.12.8 h1:n5SOGamA/HtlpWAIXxKXpuGq1ta3wDpyOftDgjIcNHU= cloud.google.com/go/workflows v1.12.8/go.mod h1:b7akG38W6lHmyPc+WYJxIYl1rEv79bBMYVwEZmp3aJQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 h1:oVLqHXhnYtUwM89y9T1fXGaK9wTkXHgNp8/ZNMQzUxE= github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= github.com/apex/logs v1.0.0 h1:adOwhOTeXzZTnVuEK13wuJNBFutP0sOfutRS8NY+G6A= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a h1:2KLQMJ8msqoPHIPDufkxVcoTtcmE5+1sL9950m4R9Pk= github.com/aphistic/sweet v0.2.0 h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/aws/aws-sdk-go v1.20.6 h1:kmy4Gvdlyez1fV4kw5RYxZzWKVyuHZHgPWeU/YvRsV4= github.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c h1:+0HFd5KSZ/mm3JmhmrDukiId5iR6w4+BdFtfSy4yWIc= github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc= github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fasthttp/websocket v1.4.3-rc.6 h1:omHqsl8j+KXpmzRjF8bmzOSYJ8GnS0E3efi1wYT+niY= github.com/fasthttp/websocket v1.4.3-rc.6/go.mod h1:43W9OM2T8FeXpCWMsBd9Cb7nE2CACNqNvCqQCoty/Lc= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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 v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9 h1:OF1IPgv+F4NmqmJ98KTjdN97Vs1JxDPB3vbmYzV2dpk= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/consul/api v1.11.0 h1:Hw/G8TtRvOElqxVIhBzXciiSTbapq8hZ2XKZsXk5ZCE= github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3 h1:QlWt0KvWT0lq8MFppF9tsJGF+ynG7ztc2KIPhzRGk7s= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgx/v4 v4.18.0/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= 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 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/lyft/protoc-gen-star v0.5.3 h1:zSGLzsUew8RT+ZKPHc3jnf8XLaVyHzTcAFBzHtCNR20= github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU= github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc= github.com/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk= github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc= github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M= github.com/sagikazarmark/crypt v0.3.0 h1:TV5DVog+pihN4Rr0rN1IClv4ePpkzdg9sPrw7WDofZ8= github.com/sagikazarmark/crypt v0.19.0 h1:WMyLTjHBo64UvNcWqpzY3pbZTYgnemZU8FBZigKc42E= github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/savsgio/gotils v0.0.0-20210617111740-97865ed5a873 h1:N3Af8f13ooDKcIhsmFT7Z05CStZWu4C7Md0uDEy4q6o= github.com/savsgio/gotils v0.0.0-20210617111740-97865ed5a873/go.mod h1:dmPawKuiAeG/aFYVs2i+Dyosoo7FNcm+Pi8iK6ZUrX8= github.com/scryner/lfreequeue v0.0.0-20121212074822-473f33702129 h1:ORfYNrFCM8HMZkU8QFX9Z8M6NWMlQnamJpSI5s0l4cM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q= github.com/smartystreets/gunit v1.0.0 h1:RyPDUFcJbvtXlhJPk7v+wnxZRY2EUokhEYl2EJOPToI= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE= github.com/tj/go-buffer v1.1.0 h1:Lo2OsPHlIxXF24zApe15AbK3bJLAOvkkxEA6Ux4c47M= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2 h1:eGaGNxrtoZf/mBURsnNQKDR7u50Klgcf2eFDQEnc8Bc= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b h1:m74UWYy+HBs+jMFR9mdZU6shPewugMyH5+GV6LNgW8w= github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/valyala/fastrand v1.0.0 h1:LUKT9aKer2dVQNUi3waewTbKV+7H17kvWFNKs2ObdkI= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ= go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= go.einride.tech/aip v0.67.1 h1:d/4TW92OxXBngkSOwWS2CH5rez869KpKMaN44mdxkFI= go.einride.tech/aip v0.67.1/go.mod h1:ZGX4/zKw8dcgzdLsrvpOOGxfxI2QSk12SlP7d6c0/XI= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E= go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= go.etcd.io/etcd/client/v2 v2.305.1 h1:vtxYCKWA9x31w0WJj7DdqsHFNjhkigdAnziDtkZb/l4= go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sGKI= go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E= go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.62.0 h1:PhGymJMXfGBzc4lBRmrx9+1w4w2wEzURHNGF/sD/xGc= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/api v0.166.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg= google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= google.golang.org/api v0.180.0/go.mod h1:51AiyoEg1MJPSZ9zvklA8VnRILPXxn1iVen9v25XHAE= google.golang.org/api v0.182.0 h1:if5fPvudRQ78GeRx3RayIoiuV7modtErPIZC/T2bIvE= google.golang.org/api v0.182.0/go.mod h1:cGhjy4caqA5yXRzEhkHI8Y9mfyC2VLTlER2l08xaqtM= google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78 h1:YqFWYZXim8bG9v68xU8WjTZmYKb5M5dMeSOWIp6jogI= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240314234333-6e1732d8331c h1:4z0DVWmDWWZ4OeQHLrb6lLBE3uCgSLs9DDA5Zb36DFg= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240314234333-6e1732d8331c/go.mod h1:IN9OQUXZ0xT+26MDwZL8fJcYw+y99b0eYPA2U15Jt8o= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240521202816-d264139d666e h1:Px+x8PNp8izq1ORW6jI007V/fRZ3bWrgcWHImtBduXc= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240521202816-d264139d666e/go.mod h1:0J6mmn3XAEjfNbPvpH63c0RXCjGNFcCzlEfWSN4In+k= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240722135656-d784300faade h1:fc+h2kSr2nW2DHxAdGYeX3bnkr4iFsKHUu9Fi6Rh4Y8= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240722135656-d784300faade/go.mod h1:5/MT647Cn/GGhwTpXC7QqcaR5Cnee4v4MKCU1/nwnIQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= modernc.org/b v1.0.2 h1:iPC2u39ebzq12GOC2yXT4mve0HrWcH85cz+midWjzeo= modernc.org/db v1.0.3 h1:apxOlWU69je04bY22OT6J0RL23mzvUy22EgTAVyw+Yg= modernc.org/file v1.0.3 h1:McYGAMMuqjRp6ptmpcLr3r5yw3gNPsonFCAJ0tNK74U= modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w= modernc.org/golex v1.0.1 h1:EYKY1a3wStt0RzHaH8mdSRNg78Ub0OHxYfCRWw35YtM= modernc.org/internal v1.0.2 h1:Sn3+ojjMRnPaOR6jFISs6KAdRHnR4q9KNuwfKINKmZA= modernc.org/lex v1.0.0 h1:w0dxp18i1q+aSE7GkepvwzvVWTLoCIQ2oDgTFAV2JZU= modernc.org/lexer v1.0.0 h1:D2xE6YTaH7aiEC7o/+rbx6qTAEr1uY83peKwkamIdQ0= modernc.org/lldb v1.0.2 h1:LBw58xVFl01OuM5U9++tLy3wmu+PoWok6T3dHuNjcZk= modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= modernc.org/ql v1.4.0 h1:CqLAho+y4N8JwvqT7NJsYsp7YPwiRv6RE2n0n1ksSCU= modernc.org/sortutil v1.1.0 h1:oP3U4uM+NT/qBQcbg/K2iqAX0Nx7B1b6YZtq3Gk/PjM= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/zappy v1.0.3 h1:Tr+P3kclDSrvC6zYBW2hWmOmu5SjG6PtvCt3RCjRmss= nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= ================================================ FILE: grpc/.gitignore ================================================ .idea/ .DS_Store ================================================ FILE: grpc/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2021, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: grpc/README.md ================================================ # crawlab-grpc gRPC for Crawlab ================================================ FILE: grpc/bin/compile.sh ================================================ #!/bin/bash if [ -L $0 ] then BASE_DIR=`dirname $(readlink $0)` else BASE_DIR=`dirname $0` fi base_path=$(cd $BASE_DIR/..; pwd) cd $base_path && \ protoc -I ./proto \ --go_out=. \ --go-grpc_out=. \ ./proto/**/*.proto ================================================ FILE: grpc/bin/compile_all.sh ================================================ #!/bin/bash if [ -L $0 ] then BASE_DIR=`dirname $(readlink $0)` else BASE_DIR=`dirname $0` fi base_path=$(cd $BASE_DIR/..; pwd) cd $base_path && \ rm -rf dist | true cd $base_path && \ mkdir -p dist/python | true && \ mkdir -p dist/js | true && \ mkdir -p dist/ts | true && \ mkdir -p dist/java | true && \ mkdir -p dist/csharp | true && \ mkdir -p dist/php | true && \ mkdir -p dist/ruby | true cd $base_path && \ protoc -I ./proto \ --go_out=. \ --go-grpc_out=. \ --python_out=dist/python \ --js_out=dist/js \ --java_out=dist/java \ --csharp_out=dist/csharp \ ./proto/**/*.proto # python cd $base_path && \ python3 -m grpc_tools.protoc -I ./proto \ --grpc_python_out=dist/python \ ./proto/**/*.proto ================================================ FILE: grpc/dependencies_service_v2.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/dependencies_service_v2.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type DependenciesServiceV2Code int32 const ( DependenciesServiceV2Code_SYNC DependenciesServiceV2Code = 0 DependenciesServiceV2Code_INSTALL DependenciesServiceV2Code = 1 DependenciesServiceV2Code_UNINSTALL DependenciesServiceV2Code = 2 ) // Enum value maps for DependenciesServiceV2Code. var ( DependenciesServiceV2Code_name = map[int32]string{ 0: "SYNC", 1: "INSTALL", 2: "UNINSTALL", } DependenciesServiceV2Code_value = map[string]int32{ "SYNC": 0, "INSTALL": 1, "UNINSTALL": 2, } ) func (x DependenciesServiceV2Code) Enum() *DependenciesServiceV2Code { p := new(DependenciesServiceV2Code) *p = x return p } func (x DependenciesServiceV2Code) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (DependenciesServiceV2Code) Descriptor() protoreflect.EnumDescriptor { return file_services_dependencies_service_v2_proto_enumTypes[0].Descriptor() } func (DependenciesServiceV2Code) Type() protoreflect.EnumType { return &file_services_dependencies_service_v2_proto_enumTypes[0] } func (x DependenciesServiceV2Code) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use DependenciesServiceV2Code.Descriptor instead. func (DependenciesServiceV2Code) EnumDescriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{0} } type Dependency struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` } func (x *Dependency) Reset() { *x = Dependency{} if protoimpl.UnsafeEnabled { mi := &file_services_dependencies_service_v2_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Dependency) String() string { return protoimpl.X.MessageStringOf(x) } func (*Dependency) ProtoMessage() {} func (x *Dependency) ProtoReflect() protoreflect.Message { mi := &file_services_dependencies_service_v2_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Dependency.ProtoReflect.Descriptor instead. func (*Dependency) Descriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{0} } func (x *Dependency) GetName() string { if x != nil { return x.Name } return "" } func (x *Dependency) GetVersion() string { if x != nil { return x.Version } return "" } type DependenciesServiceV2ConnectRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` } func (x *DependenciesServiceV2ConnectRequest) Reset() { *x = DependenciesServiceV2ConnectRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_dependencies_service_v2_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *DependenciesServiceV2ConnectRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*DependenciesServiceV2ConnectRequest) ProtoMessage() {} func (x *DependenciesServiceV2ConnectRequest) ProtoReflect() protoreflect.Message { mi := &file_services_dependencies_service_v2_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use DependenciesServiceV2ConnectRequest.ProtoReflect.Descriptor instead. func (*DependenciesServiceV2ConnectRequest) Descriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{1} } func (x *DependenciesServiceV2ConnectRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } type DependenciesServiceV2ConnectResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Code DependenciesServiceV2Code `protobuf:"varint,1,opt,name=code,proto3,enum=grpc.DependenciesServiceV2Code" json:"code,omitempty"` TaskId string `protobuf:"bytes,2,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` Lang string `protobuf:"bytes,3,opt,name=lang,proto3" json:"lang,omitempty"` Proxy string `protobuf:"bytes,4,opt,name=proxy,proto3" json:"proxy,omitempty"` Dependencies []*Dependency `protobuf:"bytes,5,rep,name=dependencies,proto3" json:"dependencies,omitempty"` } func (x *DependenciesServiceV2ConnectResponse) Reset() { *x = DependenciesServiceV2ConnectResponse{} if protoimpl.UnsafeEnabled { mi := &file_services_dependencies_service_v2_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *DependenciesServiceV2ConnectResponse) String() string { return protoimpl.X.MessageStringOf(x) } func (*DependenciesServiceV2ConnectResponse) ProtoMessage() {} func (x *DependenciesServiceV2ConnectResponse) ProtoReflect() protoreflect.Message { mi := &file_services_dependencies_service_v2_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use DependenciesServiceV2ConnectResponse.ProtoReflect.Descriptor instead. func (*DependenciesServiceV2ConnectResponse) Descriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{2} } func (x *DependenciesServiceV2ConnectResponse) GetCode() DependenciesServiceV2Code { if x != nil { return x.Code } return DependenciesServiceV2Code_SYNC } func (x *DependenciesServiceV2ConnectResponse) GetTaskId() string { if x != nil { return x.TaskId } return "" } func (x *DependenciesServiceV2ConnectResponse) GetLang() string { if x != nil { return x.Lang } return "" } func (x *DependenciesServiceV2ConnectResponse) GetProxy() string { if x != nil { return x.Proxy } return "" } func (x *DependenciesServiceV2ConnectResponse) GetDependencies() []*Dependency { if x != nil { return x.Dependencies } return nil } type DependenciesServiceV2SyncRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` Lang string `protobuf:"bytes,2,opt,name=lang,proto3" json:"lang,omitempty"` Dependencies []*Dependency `protobuf:"bytes,3,rep,name=dependencies,proto3" json:"dependencies,omitempty"` } func (x *DependenciesServiceV2SyncRequest) Reset() { *x = DependenciesServiceV2SyncRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_dependencies_service_v2_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *DependenciesServiceV2SyncRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*DependenciesServiceV2SyncRequest) ProtoMessage() {} func (x *DependenciesServiceV2SyncRequest) ProtoReflect() protoreflect.Message { mi := &file_services_dependencies_service_v2_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use DependenciesServiceV2SyncRequest.ProtoReflect.Descriptor instead. func (*DependenciesServiceV2SyncRequest) Descriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{3} } func (x *DependenciesServiceV2SyncRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *DependenciesServiceV2SyncRequest) GetLang() string { if x != nil { return x.Lang } return "" } func (x *DependenciesServiceV2SyncRequest) GetDependencies() []*Dependency { if x != nil { return x.Dependencies } return nil } type DependenciesServiceV2UpdateTaskLogRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` LogLines []string `protobuf:"bytes,2,rep,name=log_lines,json=logLines,proto3" json:"log_lines,omitempty"` } func (x *DependenciesServiceV2UpdateTaskLogRequest) Reset() { *x = DependenciesServiceV2UpdateTaskLogRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_dependencies_service_v2_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *DependenciesServiceV2UpdateTaskLogRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*DependenciesServiceV2UpdateTaskLogRequest) ProtoMessage() {} func (x *DependenciesServiceV2UpdateTaskLogRequest) ProtoReflect() protoreflect.Message { mi := &file_services_dependencies_service_v2_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use DependenciesServiceV2UpdateTaskLogRequest.ProtoReflect.Descriptor instead. func (*DependenciesServiceV2UpdateTaskLogRequest) Descriptor() ([]byte, []int) { return file_services_dependencies_service_v2_proto_rawDescGZIP(), []int{4} } func (x *DependenciesServiceV2UpdateTaskLogRequest) GetTaskId() string { if x != nil { return x.TaskId } return "" } func (x *DependenciesServiceV2UpdateTaskLogRequest) GetLogLines() []string { if x != nil { return x.LogLines } return nil } var File_services_dependencies_service_v2_proto protoreflect.FileDescriptor var file_services_dependencies_service_v2_proto_rawDesc = []byte{ 0x0a, 0x26, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3a, 0x0a, 0x0a, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x40, 0x0a, 0x23, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x22, 0xd4, 0x01, 0x0a, 0x24, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x34, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x20, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0x61, 0x0a, 0x29, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x2a, 0x41, 0x0a, 0x19, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x32, 0x95, 0x02, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x12, 0x64, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x29, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x40, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_services_dependencies_service_v2_proto_rawDescOnce sync.Once file_services_dependencies_service_v2_proto_rawDescData = file_services_dependencies_service_v2_proto_rawDesc ) func file_services_dependencies_service_v2_proto_rawDescGZIP() []byte { file_services_dependencies_service_v2_proto_rawDescOnce.Do(func() { file_services_dependencies_service_v2_proto_rawDescData = protoimpl.X.CompressGZIP(file_services_dependencies_service_v2_proto_rawDescData) }) return file_services_dependencies_service_v2_proto_rawDescData } var file_services_dependencies_service_v2_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_services_dependencies_service_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_services_dependencies_service_v2_proto_goTypes = []any{ (DependenciesServiceV2Code)(0), // 0: grpc.DependenciesServiceV2Code (*Dependency)(nil), // 1: grpc.Dependency (*DependenciesServiceV2ConnectRequest)(nil), // 2: grpc.DependenciesServiceV2ConnectRequest (*DependenciesServiceV2ConnectResponse)(nil), // 3: grpc.DependenciesServiceV2ConnectResponse (*DependenciesServiceV2SyncRequest)(nil), // 4: grpc.DependenciesServiceV2SyncRequest (*DependenciesServiceV2UpdateTaskLogRequest)(nil), // 5: grpc.DependenciesServiceV2UpdateTaskLogRequest (*Response)(nil), // 6: grpc.Response } var file_services_dependencies_service_v2_proto_depIdxs = []int32{ 0, // 0: grpc.DependenciesServiceV2ConnectResponse.code:type_name -> grpc.DependenciesServiceV2Code 1, // 1: grpc.DependenciesServiceV2ConnectResponse.dependencies:type_name -> grpc.Dependency 1, // 2: grpc.DependenciesServiceV2SyncRequest.dependencies:type_name -> grpc.Dependency 2, // 3: grpc.DependenciesServiceV2.Connect:input_type -> grpc.DependenciesServiceV2ConnectRequest 4, // 4: grpc.DependenciesServiceV2.Sync:input_type -> grpc.DependenciesServiceV2SyncRequest 5, // 5: grpc.DependenciesServiceV2.UpdateTaskLog:input_type -> grpc.DependenciesServiceV2UpdateTaskLogRequest 3, // 6: grpc.DependenciesServiceV2.Connect:output_type -> grpc.DependenciesServiceV2ConnectResponse 6, // 7: grpc.DependenciesServiceV2.Sync:output_type -> grpc.Response 6, // 8: grpc.DependenciesServiceV2.UpdateTaskLog:output_type -> grpc.Response 6, // [6:9] is the sub-list for method output_type 3, // [3:6] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name 3, // [3:3] is the sub-list for extension extendee 0, // [0:3] is the sub-list for field type_name } func init() { file_services_dependencies_service_v2_proto_init() } func file_services_dependencies_service_v2_proto_init() { if File_services_dependencies_service_v2_proto != nil { return } file_entity_response_proto_init() if !protoimpl.UnsafeEnabled { file_services_dependencies_service_v2_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Dependency); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_services_dependencies_service_v2_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*DependenciesServiceV2ConnectRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_services_dependencies_service_v2_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*DependenciesServiceV2ConnectResponse); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_services_dependencies_service_v2_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*DependenciesServiceV2SyncRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_services_dependencies_service_v2_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*DependenciesServiceV2UpdateTaskLogRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_dependencies_service_v2_proto_rawDesc, NumEnums: 1, NumMessages: 5, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_dependencies_service_v2_proto_goTypes, DependencyIndexes: file_services_dependencies_service_v2_proto_depIdxs, EnumInfos: file_services_dependencies_service_v2_proto_enumTypes, MessageInfos: file_services_dependencies_service_v2_proto_msgTypes, }.Build() File_services_dependencies_service_v2_proto = out.File file_services_dependencies_service_v2_proto_rawDesc = nil file_services_dependencies_service_v2_proto_goTypes = nil file_services_dependencies_service_v2_proto_depIdxs = nil } ================================================ FILE: grpc/dependencies_service_v2_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/dependencies_service_v2.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( DependenciesServiceV2_Connect_FullMethodName = "/grpc.DependenciesServiceV2/Connect" DependenciesServiceV2_Sync_FullMethodName = "/grpc.DependenciesServiceV2/Sync" DependenciesServiceV2_UpdateTaskLog_FullMethodName = "/grpc.DependenciesServiceV2/UpdateTaskLog" ) // DependenciesServiceV2Client is the client API for DependenciesServiceV2 service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type DependenciesServiceV2Client interface { Connect(ctx context.Context, in *DependenciesServiceV2ConnectRequest, opts ...grpc.CallOption) (DependenciesServiceV2_ConnectClient, error) Sync(ctx context.Context, in *DependenciesServiceV2SyncRequest, opts ...grpc.CallOption) (*Response, error) UpdateTaskLog(ctx context.Context, opts ...grpc.CallOption) (DependenciesServiceV2_UpdateTaskLogClient, error) } type dependenciesServiceV2Client struct { cc grpc.ClientConnInterface } func NewDependenciesServiceV2Client(cc grpc.ClientConnInterface) DependenciesServiceV2Client { return &dependenciesServiceV2Client{cc} } func (c *dependenciesServiceV2Client) Connect(ctx context.Context, in *DependenciesServiceV2ConnectRequest, opts ...grpc.CallOption) (DependenciesServiceV2_ConnectClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &DependenciesServiceV2_ServiceDesc.Streams[0], DependenciesServiceV2_Connect_FullMethodName, cOpts...) if err != nil { return nil, err } x := &dependenciesServiceV2ConnectClient{ClientStream: stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } if err := x.ClientStream.CloseSend(); err != nil { return nil, err } return x, nil } type DependenciesServiceV2_ConnectClient interface { Recv() (*DependenciesServiceV2ConnectResponse, error) grpc.ClientStream } type dependenciesServiceV2ConnectClient struct { grpc.ClientStream } func (x *dependenciesServiceV2ConnectClient) Recv() (*DependenciesServiceV2ConnectResponse, error) { m := new(DependenciesServiceV2ConnectResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *dependenciesServiceV2Client) Sync(ctx context.Context, in *DependenciesServiceV2SyncRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, DependenciesServiceV2_Sync_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *dependenciesServiceV2Client) UpdateTaskLog(ctx context.Context, opts ...grpc.CallOption) (DependenciesServiceV2_UpdateTaskLogClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &DependenciesServiceV2_ServiceDesc.Streams[1], DependenciesServiceV2_UpdateTaskLog_FullMethodName, cOpts...) if err != nil { return nil, err } x := &dependenciesServiceV2UpdateTaskLogClient{ClientStream: stream} return x, nil } type DependenciesServiceV2_UpdateTaskLogClient interface { Send(*DependenciesServiceV2UpdateTaskLogRequest) error CloseAndRecv() (*Response, error) grpc.ClientStream } type dependenciesServiceV2UpdateTaskLogClient struct { grpc.ClientStream } func (x *dependenciesServiceV2UpdateTaskLogClient) Send(m *DependenciesServiceV2UpdateTaskLogRequest) error { return x.ClientStream.SendMsg(m) } func (x *dependenciesServiceV2UpdateTaskLogClient) CloseAndRecv() (*Response, error) { if err := x.ClientStream.CloseSend(); err != nil { return nil, err } m := new(Response) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // DependenciesServiceV2Server is the server API for DependenciesServiceV2 service. // All implementations must embed UnimplementedDependenciesServiceV2Server // for forward compatibility type DependenciesServiceV2Server interface { Connect(*DependenciesServiceV2ConnectRequest, DependenciesServiceV2_ConnectServer) error Sync(context.Context, *DependenciesServiceV2SyncRequest) (*Response, error) UpdateTaskLog(DependenciesServiceV2_UpdateTaskLogServer) error mustEmbedUnimplementedDependenciesServiceV2Server() } // UnimplementedDependenciesServiceV2Server must be embedded to have forward compatible implementations. type UnimplementedDependenciesServiceV2Server struct { } func (UnimplementedDependenciesServiceV2Server) Connect(*DependenciesServiceV2ConnectRequest, DependenciesServiceV2_ConnectServer) error { return status.Errorf(codes.Unimplemented, "method Connect not implemented") } func (UnimplementedDependenciesServiceV2Server) Sync(context.Context, *DependenciesServiceV2SyncRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Sync not implemented") } func (UnimplementedDependenciesServiceV2Server) UpdateTaskLog(DependenciesServiceV2_UpdateTaskLogServer) error { return status.Errorf(codes.Unimplemented, "method UpdateTaskLog not implemented") } func (UnimplementedDependenciesServiceV2Server) mustEmbedUnimplementedDependenciesServiceV2Server() {} // UnsafeDependenciesServiceV2Server may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to DependenciesServiceV2Server will // result in compilation errors. type UnsafeDependenciesServiceV2Server interface { mustEmbedUnimplementedDependenciesServiceV2Server() } func RegisterDependenciesServiceV2Server(s grpc.ServiceRegistrar, srv DependenciesServiceV2Server) { s.RegisterService(&DependenciesServiceV2_ServiceDesc, srv) } func _DependenciesServiceV2_Connect_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(DependenciesServiceV2ConnectRequest) if err := stream.RecvMsg(m); err != nil { return err } return srv.(DependenciesServiceV2Server).Connect(m, &dependenciesServiceV2ConnectServer{ServerStream: stream}) } type DependenciesServiceV2_ConnectServer interface { Send(*DependenciesServiceV2ConnectResponse) error grpc.ServerStream } type dependenciesServiceV2ConnectServer struct { grpc.ServerStream } func (x *dependenciesServiceV2ConnectServer) Send(m *DependenciesServiceV2ConnectResponse) error { return x.ServerStream.SendMsg(m) } func _DependenciesServiceV2_Sync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DependenciesServiceV2SyncRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(DependenciesServiceV2Server).Sync(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: DependenciesServiceV2_Sync_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(DependenciesServiceV2Server).Sync(ctx, req.(*DependenciesServiceV2SyncRequest)) } return interceptor(ctx, in, info, handler) } func _DependenciesServiceV2_UpdateTaskLog_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(DependenciesServiceV2Server).UpdateTaskLog(&dependenciesServiceV2UpdateTaskLogServer{ServerStream: stream}) } type DependenciesServiceV2_UpdateTaskLogServer interface { SendAndClose(*Response) error Recv() (*DependenciesServiceV2UpdateTaskLogRequest, error) grpc.ServerStream } type dependenciesServiceV2UpdateTaskLogServer struct { grpc.ServerStream } func (x *dependenciesServiceV2UpdateTaskLogServer) SendAndClose(m *Response) error { return x.ServerStream.SendMsg(m) } func (x *dependenciesServiceV2UpdateTaskLogServer) Recv() (*DependenciesServiceV2UpdateTaskLogRequest, error) { m := new(DependenciesServiceV2UpdateTaskLogRequest) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // DependenciesServiceV2_ServiceDesc is the grpc.ServiceDesc for DependenciesServiceV2 service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var DependenciesServiceV2_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.DependenciesServiceV2", HandlerType: (*DependenciesServiceV2Server)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Sync", Handler: _DependenciesServiceV2_Sync_Handler, }, }, Streams: []grpc.StreamDesc{ { StreamName: "Connect", Handler: _DependenciesServiceV2_Connect_Handler, ServerStreams: true, }, { StreamName: "UpdateTaskLog", Handler: _DependenciesServiceV2_UpdateTaskLog_Handler, ClientStreams: true, }, }, Metadata: "services/dependencies_service_v2.proto", } ================================================ FILE: grpc/go.mod ================================================ module github.com/crawlab-team/crawlab/grpc go 1.22 require ( google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.34.2 ) require ( golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect ) ================================================ FILE: grpc/go.sum ================================================ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= ================================================ FILE: grpc/message_service.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/message_service.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) var File_services_message_service_proto protoreflect.FileDescriptor var file_services_message_service_proto_rawDesc = []byte{ 0x0a, 0x1e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x4b, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_services_message_service_proto_goTypes = []any{ (*StreamMessage)(nil), // 0: grpc.StreamMessage } var file_services_message_service_proto_depIdxs = []int32{ 0, // 0: grpc.MessageService.Connect:input_type -> grpc.StreamMessage 0, // 1: grpc.MessageService.Connect:output_type -> grpc.StreamMessage 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_message_service_proto_init() } func file_services_message_service_proto_init() { if File_services_message_service_proto != nil { return } file_entity_stream_message_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_message_service_proto_rawDesc, NumEnums: 0, NumMessages: 0, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_message_service_proto_goTypes, DependencyIndexes: file_services_message_service_proto_depIdxs, }.Build() File_services_message_service_proto = out.File file_services_message_service_proto_rawDesc = nil file_services_message_service_proto_goTypes = nil file_services_message_service_proto_depIdxs = nil } ================================================ FILE: grpc/message_service_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/message_service.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( MessageService_Connect_FullMethodName = "/grpc.MessageService/Connect" ) // MessageServiceClient is the client API for MessageService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type MessageServiceClient interface { Connect(ctx context.Context, opts ...grpc.CallOption) (MessageService_ConnectClient, error) } type messageServiceClient struct { cc grpc.ClientConnInterface } func NewMessageServiceClient(cc grpc.ClientConnInterface) MessageServiceClient { return &messageServiceClient{cc} } func (c *messageServiceClient) Connect(ctx context.Context, opts ...grpc.CallOption) (MessageService_ConnectClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &MessageService_ServiceDesc.Streams[0], MessageService_Connect_FullMethodName, cOpts...) if err != nil { return nil, err } x := &messageServiceConnectClient{ClientStream: stream} return x, nil } type MessageService_ConnectClient interface { Send(*StreamMessage) error Recv() (*StreamMessage, error) grpc.ClientStream } type messageServiceConnectClient struct { grpc.ClientStream } func (x *messageServiceConnectClient) Send(m *StreamMessage) error { return x.ClientStream.SendMsg(m) } func (x *messageServiceConnectClient) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // MessageServiceServer is the server API for MessageService service. // All implementations must embed UnimplementedMessageServiceServer // for forward compatibility type MessageServiceServer interface { Connect(MessageService_ConnectServer) error mustEmbedUnimplementedMessageServiceServer() } // UnimplementedMessageServiceServer must be embedded to have forward compatible implementations. type UnimplementedMessageServiceServer struct { } func (UnimplementedMessageServiceServer) Connect(MessageService_ConnectServer) error { return status.Errorf(codes.Unimplemented, "method Connect not implemented") } func (UnimplementedMessageServiceServer) mustEmbedUnimplementedMessageServiceServer() {} // UnsafeMessageServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to MessageServiceServer will // result in compilation errors. type UnsafeMessageServiceServer interface { mustEmbedUnimplementedMessageServiceServer() } func RegisterMessageServiceServer(s grpc.ServiceRegistrar, srv MessageServiceServer) { s.RegisterService(&MessageService_ServiceDesc, srv) } func _MessageService_Connect_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(MessageServiceServer).Connect(&messageServiceConnectServer{ServerStream: stream}) } type MessageService_ConnectServer interface { Send(*StreamMessage) error Recv() (*StreamMessage, error) grpc.ServerStream } type messageServiceConnectServer struct { grpc.ServerStream } func (x *messageServiceConnectServer) Send(m *StreamMessage) error { return x.ServerStream.SendMsg(m) } func (x *messageServiceConnectServer) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // MessageService_ServiceDesc is the grpc.ServiceDesc for MessageService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var MessageService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.MessageService", HandlerType: (*MessageServiceServer)(nil), Methods: []grpc.MethodDesc{}, Streams: []grpc.StreamDesc{ { StreamName: "Connect", Handler: _MessageService_Connect_Handler, ServerStreams: true, ClientStreams: true, }, }, Metadata: "services/message_service.proto", } ================================================ FILE: grpc/metrics_service_v2.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/metrics_service_v2.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type MetricsServiceV2SendRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` NodeKey string `protobuf:"bytes,2,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` CpuUsagePercent float32 `protobuf:"fixed32,4,opt,name=cpu_usage_percent,json=cpuUsagePercent,proto3" json:"cpu_usage_percent,omitempty"` TotalMemory uint64 `protobuf:"varint,5,opt,name=total_memory,json=totalMemory,proto3" json:"total_memory,omitempty"` AvailableMemory uint64 `protobuf:"varint,6,opt,name=available_memory,json=availableMemory,proto3" json:"available_memory,omitempty"` UsedMemory uint64 `protobuf:"varint,7,opt,name=used_memory,json=usedMemory,proto3" json:"used_memory,omitempty"` UsedMemoryPercent float32 `protobuf:"fixed32,8,opt,name=used_memory_percent,json=usedMemoryPercent,proto3" json:"used_memory_percent,omitempty"` TotalDisk uint64 `protobuf:"varint,9,opt,name=total_disk,json=totalDisk,proto3" json:"total_disk,omitempty"` AvailableDisk uint64 `protobuf:"varint,10,opt,name=available_disk,json=availableDisk,proto3" json:"available_disk,omitempty"` UsedDisk uint64 `protobuf:"varint,11,opt,name=used_disk,json=usedDisk,proto3" json:"used_disk,omitempty"` UsedDiskPercent float32 `protobuf:"fixed32,12,opt,name=used_disk_percent,json=usedDiskPercent,proto3" json:"used_disk_percent,omitempty"` DiskReadBytesRate float32 `protobuf:"fixed32,15,opt,name=disk_read_bytes_rate,json=diskReadBytesRate,proto3" json:"disk_read_bytes_rate,omitempty"` DiskWriteBytesRate float32 `protobuf:"fixed32,16,opt,name=disk_write_bytes_rate,json=diskWriteBytesRate,proto3" json:"disk_write_bytes_rate,omitempty"` NetworkBytesSentRate float32 `protobuf:"fixed32,17,opt,name=network_bytes_sent_rate,json=networkBytesSentRate,proto3" json:"network_bytes_sent_rate,omitempty"` NetworkBytesRecvRate float32 `protobuf:"fixed32,18,opt,name=network_bytes_recv_rate,json=networkBytesRecvRate,proto3" json:"network_bytes_recv_rate,omitempty"` } func (x *MetricsServiceV2SendRequest) Reset() { *x = MetricsServiceV2SendRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_metrics_service_v2_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *MetricsServiceV2SendRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*MetricsServiceV2SendRequest) ProtoMessage() {} func (x *MetricsServiceV2SendRequest) ProtoReflect() protoreflect.Message { mi := &file_services_metrics_service_v2_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use MetricsServiceV2SendRequest.ProtoReflect.Descriptor instead. func (*MetricsServiceV2SendRequest) Descriptor() ([]byte, []int) { return file_services_metrics_service_v2_proto_rawDescGZIP(), []int{0} } func (x *MetricsServiceV2SendRequest) GetType() string { if x != nil { return x.Type } return "" } func (x *MetricsServiceV2SendRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *MetricsServiceV2SendRequest) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } func (x *MetricsServiceV2SendRequest) GetCpuUsagePercent() float32 { if x != nil { return x.CpuUsagePercent } return 0 } func (x *MetricsServiceV2SendRequest) GetTotalMemory() uint64 { if x != nil { return x.TotalMemory } return 0 } func (x *MetricsServiceV2SendRequest) GetAvailableMemory() uint64 { if x != nil { return x.AvailableMemory } return 0 } func (x *MetricsServiceV2SendRequest) GetUsedMemory() uint64 { if x != nil { return x.UsedMemory } return 0 } func (x *MetricsServiceV2SendRequest) GetUsedMemoryPercent() float32 { if x != nil { return x.UsedMemoryPercent } return 0 } func (x *MetricsServiceV2SendRequest) GetTotalDisk() uint64 { if x != nil { return x.TotalDisk } return 0 } func (x *MetricsServiceV2SendRequest) GetAvailableDisk() uint64 { if x != nil { return x.AvailableDisk } return 0 } func (x *MetricsServiceV2SendRequest) GetUsedDisk() uint64 { if x != nil { return x.UsedDisk } return 0 } func (x *MetricsServiceV2SendRequest) GetUsedDiskPercent() float32 { if x != nil { return x.UsedDiskPercent } return 0 } func (x *MetricsServiceV2SendRequest) GetDiskReadBytesRate() float32 { if x != nil { return x.DiskReadBytesRate } return 0 } func (x *MetricsServiceV2SendRequest) GetDiskWriteBytesRate() float32 { if x != nil { return x.DiskWriteBytesRate } return 0 } func (x *MetricsServiceV2SendRequest) GetNetworkBytesSentRate() float32 { if x != nil { return x.NetworkBytesSentRate } return 0 } func (x *MetricsServiceV2SendRequest) GetNetworkBytesRecvRate() float32 { if x != nil { return x.NetworkBytesRecvRate } return 0 } var File_services_metrics_service_v2_proto protoreflect.FileDescriptor var file_services_metrics_service_v2_proto_rawDesc = []byte{ 0x0a, 0x21, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x05, 0x0a, 0x1b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x70, 0x75, 0x5f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0f, 0x63, 0x70, 0x75, 0x55, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x11, 0x75, 0x73, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x75, 0x73, 0x65, 0x64, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x64, 0x44, 0x69, 0x73, 0x6b, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x14, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x02, 0x52, 0x11, 0x64, 0x69, 0x73, 0x6b, 0x52, 0x65, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x02, 0x52, 0x12, 0x64, 0x69, 0x73, 0x6b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x02, 0x52, 0x14, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x42, 0x79, 0x74, 0x65, 0x73, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x02, 0x52, 0x14, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x63, 0x76, 0x52, 0x61, 0x74, 0x65, 0x32, 0x4f, 0x0a, 0x10, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x12, 0x3b, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_services_metrics_service_v2_proto_rawDescOnce sync.Once file_services_metrics_service_v2_proto_rawDescData = file_services_metrics_service_v2_proto_rawDesc ) func file_services_metrics_service_v2_proto_rawDescGZIP() []byte { file_services_metrics_service_v2_proto_rawDescOnce.Do(func() { file_services_metrics_service_v2_proto_rawDescData = protoimpl.X.CompressGZIP(file_services_metrics_service_v2_proto_rawDescData) }) return file_services_metrics_service_v2_proto_rawDescData } var file_services_metrics_service_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_services_metrics_service_v2_proto_goTypes = []any{ (*MetricsServiceV2SendRequest)(nil), // 0: grpc.MetricsServiceV2SendRequest (*Response)(nil), // 1: grpc.Response } var file_services_metrics_service_v2_proto_depIdxs = []int32{ 0, // 0: grpc.MetricsServiceV2.Send:input_type -> grpc.MetricsServiceV2SendRequest 1, // 1: grpc.MetricsServiceV2.Send:output_type -> grpc.Response 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_metrics_service_v2_proto_init() } func file_services_metrics_service_v2_proto_init() { if File_services_metrics_service_v2_proto != nil { return } file_entity_response_proto_init() if !protoimpl.UnsafeEnabled { file_services_metrics_service_v2_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*MetricsServiceV2SendRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_metrics_service_v2_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_metrics_service_v2_proto_goTypes, DependencyIndexes: file_services_metrics_service_v2_proto_depIdxs, MessageInfos: file_services_metrics_service_v2_proto_msgTypes, }.Build() File_services_metrics_service_v2_proto = out.File file_services_metrics_service_v2_proto_rawDesc = nil file_services_metrics_service_v2_proto_goTypes = nil file_services_metrics_service_v2_proto_depIdxs = nil } ================================================ FILE: grpc/metrics_service_v2_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/metrics_service_v2.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( MetricsServiceV2_Send_FullMethodName = "/grpc.MetricsServiceV2/Send" ) // MetricsServiceV2Client is the client API for MetricsServiceV2 service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type MetricsServiceV2Client interface { Send(ctx context.Context, in *MetricsServiceV2SendRequest, opts ...grpc.CallOption) (*Response, error) } type metricsServiceV2Client struct { cc grpc.ClientConnInterface } func NewMetricsServiceV2Client(cc grpc.ClientConnInterface) MetricsServiceV2Client { return &metricsServiceV2Client{cc} } func (c *metricsServiceV2Client) Send(ctx context.Context, in *MetricsServiceV2SendRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, MetricsServiceV2_Send_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // MetricsServiceV2Server is the server API for MetricsServiceV2 service. // All implementations must embed UnimplementedMetricsServiceV2Server // for forward compatibility type MetricsServiceV2Server interface { Send(context.Context, *MetricsServiceV2SendRequest) (*Response, error) mustEmbedUnimplementedMetricsServiceV2Server() } // UnimplementedMetricsServiceV2Server must be embedded to have forward compatible implementations. type UnimplementedMetricsServiceV2Server struct { } func (UnimplementedMetricsServiceV2Server) Send(context.Context, *MetricsServiceV2SendRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") } func (UnimplementedMetricsServiceV2Server) mustEmbedUnimplementedMetricsServiceV2Server() {} // UnsafeMetricsServiceV2Server may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to MetricsServiceV2Server will // result in compilation errors. type UnsafeMetricsServiceV2Server interface { mustEmbedUnimplementedMetricsServiceV2Server() } func RegisterMetricsServiceV2Server(s grpc.ServiceRegistrar, srv MetricsServiceV2Server) { s.RegisterService(&MetricsServiceV2_ServiceDesc, srv) } func _MetricsServiceV2_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MetricsServiceV2SendRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(MetricsServiceV2Server).Send(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: MetricsServiceV2_Send_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MetricsServiceV2Server).Send(ctx, req.(*MetricsServiceV2SendRequest)) } return interceptor(ctx, in, info, handler) } // MetricsServiceV2_ServiceDesc is the grpc.ServiceDesc for MetricsServiceV2 service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var MetricsServiceV2_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.MetricsServiceV2", HandlerType: (*MetricsServiceV2Server)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Send", Handler: _MetricsServiceV2_Send_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "services/metrics_service_v2.proto", } ================================================ FILE: grpc/model_base_service.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/model_base_service.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) var File_services_model_base_service_proto protoreflect.FileDescriptor var file_services_model_base_service_proto_rawDesc = []byte{ 0x0a, 0x21, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x14, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xac, 0x04, 0x0a, 0x10, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x63, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x06, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x28, 0x0a, 0x05, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_services_model_base_service_proto_goTypes = []any{ (*Request)(nil), // 0: grpc.Request (*Response)(nil), // 1: grpc.Response } var file_services_model_base_service_proto_depIdxs = []int32{ 0, // 0: grpc.ModelBaseService.GetById:input_type -> grpc.Request 0, // 1: grpc.ModelBaseService.Get:input_type -> grpc.Request 0, // 2: grpc.ModelBaseService.GetList:input_type -> grpc.Request 0, // 3: grpc.ModelBaseService.DeleteById:input_type -> grpc.Request 0, // 4: grpc.ModelBaseService.Delete:input_type -> grpc.Request 0, // 5: grpc.ModelBaseService.DeleteList:input_type -> grpc.Request 0, // 6: grpc.ModelBaseService.ForceDeleteList:input_type -> grpc.Request 0, // 7: grpc.ModelBaseService.UpdateById:input_type -> grpc.Request 0, // 8: grpc.ModelBaseService.Update:input_type -> grpc.Request 0, // 9: grpc.ModelBaseService.UpdateDoc:input_type -> grpc.Request 0, // 10: grpc.ModelBaseService.Insert:input_type -> grpc.Request 0, // 11: grpc.ModelBaseService.Count:input_type -> grpc.Request 1, // 12: grpc.ModelBaseService.GetById:output_type -> grpc.Response 1, // 13: grpc.ModelBaseService.Get:output_type -> grpc.Response 1, // 14: grpc.ModelBaseService.GetList:output_type -> grpc.Response 1, // 15: grpc.ModelBaseService.DeleteById:output_type -> grpc.Response 1, // 16: grpc.ModelBaseService.Delete:output_type -> grpc.Response 1, // 17: grpc.ModelBaseService.DeleteList:output_type -> grpc.Response 1, // 18: grpc.ModelBaseService.ForceDeleteList:output_type -> grpc.Response 1, // 19: grpc.ModelBaseService.UpdateById:output_type -> grpc.Response 1, // 20: grpc.ModelBaseService.Update:output_type -> grpc.Response 1, // 21: grpc.ModelBaseService.UpdateDoc:output_type -> grpc.Response 1, // 22: grpc.ModelBaseService.Insert:output_type -> grpc.Response 1, // 23: grpc.ModelBaseService.Count:output_type -> grpc.Response 12, // [12:24] is the sub-list for method output_type 0, // [0:12] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_model_base_service_proto_init() } func file_services_model_base_service_proto_init() { if File_services_model_base_service_proto != nil { return } file_entity_request_proto_init() file_entity_response_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_model_base_service_proto_rawDesc, NumEnums: 0, NumMessages: 0, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_model_base_service_proto_goTypes, DependencyIndexes: file_services_model_base_service_proto_depIdxs, }.Build() File_services_model_base_service_proto = out.File file_services_model_base_service_proto_rawDesc = nil file_services_model_base_service_proto_goTypes = nil file_services_model_base_service_proto_depIdxs = nil } ================================================ FILE: grpc/model_base_service_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/model_base_service.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( ModelBaseService_GetById_FullMethodName = "/grpc.ModelBaseService/GetById" ModelBaseService_Get_FullMethodName = "/grpc.ModelBaseService/Get" ModelBaseService_GetList_FullMethodName = "/grpc.ModelBaseService/GetList" ModelBaseService_DeleteById_FullMethodName = "/grpc.ModelBaseService/DeleteById" ModelBaseService_Delete_FullMethodName = "/grpc.ModelBaseService/Delete" ModelBaseService_DeleteList_FullMethodName = "/grpc.ModelBaseService/DeleteList" ModelBaseService_ForceDeleteList_FullMethodName = "/grpc.ModelBaseService/ForceDeleteList" ModelBaseService_UpdateById_FullMethodName = "/grpc.ModelBaseService/UpdateById" ModelBaseService_Update_FullMethodName = "/grpc.ModelBaseService/Update" ModelBaseService_UpdateDoc_FullMethodName = "/grpc.ModelBaseService/UpdateDoc" ModelBaseService_Insert_FullMethodName = "/grpc.ModelBaseService/Insert" ModelBaseService_Count_FullMethodName = "/grpc.ModelBaseService/Count" ) // ModelBaseServiceClient is the client API for ModelBaseService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ModelBaseServiceClient interface { GetById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Get(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) GetList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) DeleteById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Delete(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) DeleteList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) ForceDeleteList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) UpdateById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Update(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) UpdateDoc(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Insert(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Count(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) } type modelBaseServiceClient struct { cc grpc.ClientConnInterface } func NewModelBaseServiceClient(cc grpc.ClientConnInterface) ModelBaseServiceClient { return &modelBaseServiceClient{cc} } func (c *modelBaseServiceClient) GetById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_GetById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) Get(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) GetList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_GetList_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) DeleteById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_DeleteById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) Delete(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) DeleteList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_DeleteList_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) ForceDeleteList(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_ForceDeleteList_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) UpdateById(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_UpdateById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) Update(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) UpdateDoc(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_UpdateDoc_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) Insert(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_Insert_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceClient) Count(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseService_Count_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // ModelBaseServiceServer is the server API for ModelBaseService service. // All implementations must embed UnimplementedModelBaseServiceServer // for forward compatibility type ModelBaseServiceServer interface { GetById(context.Context, *Request) (*Response, error) Get(context.Context, *Request) (*Response, error) GetList(context.Context, *Request) (*Response, error) DeleteById(context.Context, *Request) (*Response, error) Delete(context.Context, *Request) (*Response, error) DeleteList(context.Context, *Request) (*Response, error) ForceDeleteList(context.Context, *Request) (*Response, error) UpdateById(context.Context, *Request) (*Response, error) Update(context.Context, *Request) (*Response, error) UpdateDoc(context.Context, *Request) (*Response, error) Insert(context.Context, *Request) (*Response, error) Count(context.Context, *Request) (*Response, error) mustEmbedUnimplementedModelBaseServiceServer() } // UnimplementedModelBaseServiceServer must be embedded to have forward compatible implementations. type UnimplementedModelBaseServiceServer struct { } func (UnimplementedModelBaseServiceServer) GetById(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method GetById not implemented") } func (UnimplementedModelBaseServiceServer) Get(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } func (UnimplementedModelBaseServiceServer) GetList(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method GetList not implemented") } func (UnimplementedModelBaseServiceServer) DeleteById(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteById not implemented") } func (UnimplementedModelBaseServiceServer) Delete(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedModelBaseServiceServer) DeleteList(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteList not implemented") } func (UnimplementedModelBaseServiceServer) ForceDeleteList(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method ForceDeleteList not implemented") } func (UnimplementedModelBaseServiceServer) UpdateById(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateById not implemented") } func (UnimplementedModelBaseServiceServer) Update(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") } func (UnimplementedModelBaseServiceServer) UpdateDoc(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateDoc not implemented") } func (UnimplementedModelBaseServiceServer) Insert(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Insert not implemented") } func (UnimplementedModelBaseServiceServer) Count(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Count not implemented") } func (UnimplementedModelBaseServiceServer) mustEmbedUnimplementedModelBaseServiceServer() {} // UnsafeModelBaseServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ModelBaseServiceServer will // result in compilation errors. type UnsafeModelBaseServiceServer interface { mustEmbedUnimplementedModelBaseServiceServer() } func RegisterModelBaseServiceServer(s grpc.ServiceRegistrar, srv ModelBaseServiceServer) { s.RegisterService(&ModelBaseService_ServiceDesc, srv) } func _ModelBaseService_GetById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).GetById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_GetById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).GetById(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).Get(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_Get_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).Get(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_GetList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).GetList(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_GetList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).GetList(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_DeleteById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).DeleteById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_DeleteById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).DeleteById(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).Delete(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_Delete_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).Delete(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_DeleteList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).DeleteList(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_DeleteList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).DeleteList(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_ForceDeleteList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).ForceDeleteList(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_ForceDeleteList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).ForceDeleteList(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_UpdateById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).UpdateById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_UpdateById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).UpdateById(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).Update(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_Update_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).Update(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_UpdateDoc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).UpdateDoc(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_UpdateDoc_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).UpdateDoc(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_Insert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).Insert(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_Insert_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).Insert(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _ModelBaseService_Count_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceServer).Count(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseService_Count_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceServer).Count(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } // ModelBaseService_ServiceDesc is the grpc.ServiceDesc for ModelBaseService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var ModelBaseService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.ModelBaseService", HandlerType: (*ModelBaseServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "GetById", Handler: _ModelBaseService_GetById_Handler, }, { MethodName: "Get", Handler: _ModelBaseService_Get_Handler, }, { MethodName: "GetList", Handler: _ModelBaseService_GetList_Handler, }, { MethodName: "DeleteById", Handler: _ModelBaseService_DeleteById_Handler, }, { MethodName: "Delete", Handler: _ModelBaseService_Delete_Handler, }, { MethodName: "DeleteList", Handler: _ModelBaseService_DeleteList_Handler, }, { MethodName: "ForceDeleteList", Handler: _ModelBaseService_ForceDeleteList_Handler, }, { MethodName: "UpdateById", Handler: _ModelBaseService_UpdateById_Handler, }, { MethodName: "Update", Handler: _ModelBaseService_Update_Handler, }, { MethodName: "UpdateDoc", Handler: _ModelBaseService_UpdateDoc_Handler, }, { MethodName: "Insert", Handler: _ModelBaseService_Insert_Handler, }, { MethodName: "Count", Handler: _ModelBaseService_Count_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "services/model_base_service.proto", } ================================================ FILE: grpc/model_base_service_v2.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/model_base_service_v2.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) var File_services_model_base_service_v2_proto protoreflect.FileDescriptor var file_services_model_base_service_v2_proto_rawDesc = []byte{ 0x0a, 0x24, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x25, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xd4, 0x07, 0x0a, 0x12, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x12, 0x3f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x12, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x12, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x6e, 0x65, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4f, 0x6e, 0x65, 0x12, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x05, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_services_model_base_service_v2_proto_goTypes = []any{ (*ModelServiceV2GetByIdRequest)(nil), // 0: grpc.ModelServiceV2GetByIdRequest (*ModelServiceV2GetOneRequest)(nil), // 1: grpc.ModelServiceV2GetOneRequest (*ModelServiceV2GetManyRequest)(nil), // 2: grpc.ModelServiceV2GetManyRequest (*ModelServiceV2DeleteByIdRequest)(nil), // 3: grpc.ModelServiceV2DeleteByIdRequest (*ModelServiceV2DeleteOneRequest)(nil), // 4: grpc.ModelServiceV2DeleteOneRequest (*ModelServiceV2DeleteManyRequest)(nil), // 5: grpc.ModelServiceV2DeleteManyRequest (*ModelServiceV2UpdateByIdRequest)(nil), // 6: grpc.ModelServiceV2UpdateByIdRequest (*ModelServiceV2UpdateOneRequest)(nil), // 7: grpc.ModelServiceV2UpdateOneRequest (*ModelServiceV2UpdateManyRequest)(nil), // 8: grpc.ModelServiceV2UpdateManyRequest (*ModelServiceV2ReplaceByIdRequest)(nil), // 9: grpc.ModelServiceV2ReplaceByIdRequest (*ModelServiceV2ReplaceOneRequest)(nil), // 10: grpc.ModelServiceV2ReplaceOneRequest (*ModelServiceV2InsertOneRequest)(nil), // 11: grpc.ModelServiceV2InsertOneRequest (*ModelServiceV2InsertManyRequest)(nil), // 12: grpc.ModelServiceV2InsertManyRequest (*ModelServiceV2CountRequest)(nil), // 13: grpc.ModelServiceV2CountRequest (*Response)(nil), // 14: grpc.Response } var file_services_model_base_service_v2_proto_depIdxs = []int32{ 0, // 0: grpc.ModelBaseServiceV2.GetById:input_type -> grpc.ModelServiceV2GetByIdRequest 1, // 1: grpc.ModelBaseServiceV2.GetOne:input_type -> grpc.ModelServiceV2GetOneRequest 2, // 2: grpc.ModelBaseServiceV2.GetMany:input_type -> grpc.ModelServiceV2GetManyRequest 3, // 3: grpc.ModelBaseServiceV2.DeleteById:input_type -> grpc.ModelServiceV2DeleteByIdRequest 4, // 4: grpc.ModelBaseServiceV2.DeleteOne:input_type -> grpc.ModelServiceV2DeleteOneRequest 5, // 5: grpc.ModelBaseServiceV2.DeleteMany:input_type -> grpc.ModelServiceV2DeleteManyRequest 6, // 6: grpc.ModelBaseServiceV2.UpdateById:input_type -> grpc.ModelServiceV2UpdateByIdRequest 7, // 7: grpc.ModelBaseServiceV2.UpdateOne:input_type -> grpc.ModelServiceV2UpdateOneRequest 8, // 8: grpc.ModelBaseServiceV2.UpdateMany:input_type -> grpc.ModelServiceV2UpdateManyRequest 9, // 9: grpc.ModelBaseServiceV2.ReplaceById:input_type -> grpc.ModelServiceV2ReplaceByIdRequest 10, // 10: grpc.ModelBaseServiceV2.ReplaceOne:input_type -> grpc.ModelServiceV2ReplaceOneRequest 11, // 11: grpc.ModelBaseServiceV2.InsertOne:input_type -> grpc.ModelServiceV2InsertOneRequest 12, // 12: grpc.ModelBaseServiceV2.InsertMany:input_type -> grpc.ModelServiceV2InsertManyRequest 13, // 13: grpc.ModelBaseServiceV2.Count:input_type -> grpc.ModelServiceV2CountRequest 14, // 14: grpc.ModelBaseServiceV2.GetById:output_type -> grpc.Response 14, // 15: grpc.ModelBaseServiceV2.GetOne:output_type -> grpc.Response 14, // 16: grpc.ModelBaseServiceV2.GetMany:output_type -> grpc.Response 14, // 17: grpc.ModelBaseServiceV2.DeleteById:output_type -> grpc.Response 14, // 18: grpc.ModelBaseServiceV2.DeleteOne:output_type -> grpc.Response 14, // 19: grpc.ModelBaseServiceV2.DeleteMany:output_type -> grpc.Response 14, // 20: grpc.ModelBaseServiceV2.UpdateById:output_type -> grpc.Response 14, // 21: grpc.ModelBaseServiceV2.UpdateOne:output_type -> grpc.Response 14, // 22: grpc.ModelBaseServiceV2.UpdateMany:output_type -> grpc.Response 14, // 23: grpc.ModelBaseServiceV2.ReplaceById:output_type -> grpc.Response 14, // 24: grpc.ModelBaseServiceV2.ReplaceOne:output_type -> grpc.Response 14, // 25: grpc.ModelBaseServiceV2.InsertOne:output_type -> grpc.Response 14, // 26: grpc.ModelBaseServiceV2.InsertMany:output_type -> grpc.Response 14, // 27: grpc.ModelBaseServiceV2.Count:output_type -> grpc.Response 14, // [14:28] is the sub-list for method output_type 0, // [0:14] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_model_base_service_v2_proto_init() } func file_services_model_base_service_v2_proto_init() { if File_services_model_base_service_v2_proto != nil { return } file_entity_model_service_v2_request_proto_init() file_entity_response_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_model_base_service_v2_proto_rawDesc, NumEnums: 0, NumMessages: 0, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_model_base_service_v2_proto_goTypes, DependencyIndexes: file_services_model_base_service_v2_proto_depIdxs, }.Build() File_services_model_base_service_v2_proto = out.File file_services_model_base_service_v2_proto_rawDesc = nil file_services_model_base_service_v2_proto_goTypes = nil file_services_model_base_service_v2_proto_depIdxs = nil } ================================================ FILE: grpc/model_base_service_v2_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/model_base_service_v2.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( ModelBaseServiceV2_GetById_FullMethodName = "/grpc.ModelBaseServiceV2/GetById" ModelBaseServiceV2_GetOne_FullMethodName = "/grpc.ModelBaseServiceV2/GetOne" ModelBaseServiceV2_GetMany_FullMethodName = "/grpc.ModelBaseServiceV2/GetMany" ModelBaseServiceV2_DeleteById_FullMethodName = "/grpc.ModelBaseServiceV2/DeleteById" ModelBaseServiceV2_DeleteOne_FullMethodName = "/grpc.ModelBaseServiceV2/DeleteOne" ModelBaseServiceV2_DeleteMany_FullMethodName = "/grpc.ModelBaseServiceV2/DeleteMany" ModelBaseServiceV2_UpdateById_FullMethodName = "/grpc.ModelBaseServiceV2/UpdateById" ModelBaseServiceV2_UpdateOne_FullMethodName = "/grpc.ModelBaseServiceV2/UpdateOne" ModelBaseServiceV2_UpdateMany_FullMethodName = "/grpc.ModelBaseServiceV2/UpdateMany" ModelBaseServiceV2_ReplaceById_FullMethodName = "/grpc.ModelBaseServiceV2/ReplaceById" ModelBaseServiceV2_ReplaceOne_FullMethodName = "/grpc.ModelBaseServiceV2/ReplaceOne" ModelBaseServiceV2_InsertOne_FullMethodName = "/grpc.ModelBaseServiceV2/InsertOne" ModelBaseServiceV2_InsertMany_FullMethodName = "/grpc.ModelBaseServiceV2/InsertMany" ModelBaseServiceV2_Count_FullMethodName = "/grpc.ModelBaseServiceV2/Count" ) // ModelBaseServiceV2Client is the client API for ModelBaseServiceV2 service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ModelBaseServiceV2Client interface { GetById(ctx context.Context, in *ModelServiceV2GetByIdRequest, opts ...grpc.CallOption) (*Response, error) GetOne(ctx context.Context, in *ModelServiceV2GetOneRequest, opts ...grpc.CallOption) (*Response, error) GetMany(ctx context.Context, in *ModelServiceV2GetManyRequest, opts ...grpc.CallOption) (*Response, error) DeleteById(ctx context.Context, in *ModelServiceV2DeleteByIdRequest, opts ...grpc.CallOption) (*Response, error) DeleteOne(ctx context.Context, in *ModelServiceV2DeleteOneRequest, opts ...grpc.CallOption) (*Response, error) DeleteMany(ctx context.Context, in *ModelServiceV2DeleteManyRequest, opts ...grpc.CallOption) (*Response, error) UpdateById(ctx context.Context, in *ModelServiceV2UpdateByIdRequest, opts ...grpc.CallOption) (*Response, error) UpdateOne(ctx context.Context, in *ModelServiceV2UpdateOneRequest, opts ...grpc.CallOption) (*Response, error) UpdateMany(ctx context.Context, in *ModelServiceV2UpdateManyRequest, opts ...grpc.CallOption) (*Response, error) ReplaceById(ctx context.Context, in *ModelServiceV2ReplaceByIdRequest, opts ...grpc.CallOption) (*Response, error) ReplaceOne(ctx context.Context, in *ModelServiceV2ReplaceOneRequest, opts ...grpc.CallOption) (*Response, error) InsertOne(ctx context.Context, in *ModelServiceV2InsertOneRequest, opts ...grpc.CallOption) (*Response, error) InsertMany(ctx context.Context, in *ModelServiceV2InsertManyRequest, opts ...grpc.CallOption) (*Response, error) Count(ctx context.Context, in *ModelServiceV2CountRequest, opts ...grpc.CallOption) (*Response, error) } type modelBaseServiceV2Client struct { cc grpc.ClientConnInterface } func NewModelBaseServiceV2Client(cc grpc.ClientConnInterface) ModelBaseServiceV2Client { return &modelBaseServiceV2Client{cc} } func (c *modelBaseServiceV2Client) GetById(ctx context.Context, in *ModelServiceV2GetByIdRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_GetById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) GetOne(ctx context.Context, in *ModelServiceV2GetOneRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_GetOne_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) GetMany(ctx context.Context, in *ModelServiceV2GetManyRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_GetMany_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) DeleteById(ctx context.Context, in *ModelServiceV2DeleteByIdRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_DeleteById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) DeleteOne(ctx context.Context, in *ModelServiceV2DeleteOneRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_DeleteOne_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) DeleteMany(ctx context.Context, in *ModelServiceV2DeleteManyRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_DeleteMany_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) UpdateById(ctx context.Context, in *ModelServiceV2UpdateByIdRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_UpdateById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) UpdateOne(ctx context.Context, in *ModelServiceV2UpdateOneRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_UpdateOne_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) UpdateMany(ctx context.Context, in *ModelServiceV2UpdateManyRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_UpdateMany_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) ReplaceById(ctx context.Context, in *ModelServiceV2ReplaceByIdRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_ReplaceById_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) ReplaceOne(ctx context.Context, in *ModelServiceV2ReplaceOneRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_ReplaceOne_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) InsertOne(ctx context.Context, in *ModelServiceV2InsertOneRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_InsertOne_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) InsertMany(ctx context.Context, in *ModelServiceV2InsertManyRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_InsertMany_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *modelBaseServiceV2Client) Count(ctx context.Context, in *ModelServiceV2CountRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelBaseServiceV2_Count_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // ModelBaseServiceV2Server is the server API for ModelBaseServiceV2 service. // All implementations must embed UnimplementedModelBaseServiceV2Server // for forward compatibility type ModelBaseServiceV2Server interface { GetById(context.Context, *ModelServiceV2GetByIdRequest) (*Response, error) GetOne(context.Context, *ModelServiceV2GetOneRequest) (*Response, error) GetMany(context.Context, *ModelServiceV2GetManyRequest) (*Response, error) DeleteById(context.Context, *ModelServiceV2DeleteByIdRequest) (*Response, error) DeleteOne(context.Context, *ModelServiceV2DeleteOneRequest) (*Response, error) DeleteMany(context.Context, *ModelServiceV2DeleteManyRequest) (*Response, error) UpdateById(context.Context, *ModelServiceV2UpdateByIdRequest) (*Response, error) UpdateOne(context.Context, *ModelServiceV2UpdateOneRequest) (*Response, error) UpdateMany(context.Context, *ModelServiceV2UpdateManyRequest) (*Response, error) ReplaceById(context.Context, *ModelServiceV2ReplaceByIdRequest) (*Response, error) ReplaceOne(context.Context, *ModelServiceV2ReplaceOneRequest) (*Response, error) InsertOne(context.Context, *ModelServiceV2InsertOneRequest) (*Response, error) InsertMany(context.Context, *ModelServiceV2InsertManyRequest) (*Response, error) Count(context.Context, *ModelServiceV2CountRequest) (*Response, error) mustEmbedUnimplementedModelBaseServiceV2Server() } // UnimplementedModelBaseServiceV2Server must be embedded to have forward compatible implementations. type UnimplementedModelBaseServiceV2Server struct { } func (UnimplementedModelBaseServiceV2Server) GetById(context.Context, *ModelServiceV2GetByIdRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method GetById not implemented") } func (UnimplementedModelBaseServiceV2Server) GetOne(context.Context, *ModelServiceV2GetOneRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method GetOne not implemented") } func (UnimplementedModelBaseServiceV2Server) GetMany(context.Context, *ModelServiceV2GetManyRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMany not implemented") } func (UnimplementedModelBaseServiceV2Server) DeleteById(context.Context, *ModelServiceV2DeleteByIdRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteById not implemented") } func (UnimplementedModelBaseServiceV2Server) DeleteOne(context.Context, *ModelServiceV2DeleteOneRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteOne not implemented") } func (UnimplementedModelBaseServiceV2Server) DeleteMany(context.Context, *ModelServiceV2DeleteManyRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteMany not implemented") } func (UnimplementedModelBaseServiceV2Server) UpdateById(context.Context, *ModelServiceV2UpdateByIdRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateById not implemented") } func (UnimplementedModelBaseServiceV2Server) UpdateOne(context.Context, *ModelServiceV2UpdateOneRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateOne not implemented") } func (UnimplementedModelBaseServiceV2Server) UpdateMany(context.Context, *ModelServiceV2UpdateManyRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateMany not implemented") } func (UnimplementedModelBaseServiceV2Server) ReplaceById(context.Context, *ModelServiceV2ReplaceByIdRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplaceById not implemented") } func (UnimplementedModelBaseServiceV2Server) ReplaceOne(context.Context, *ModelServiceV2ReplaceOneRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplaceOne not implemented") } func (UnimplementedModelBaseServiceV2Server) InsertOne(context.Context, *ModelServiceV2InsertOneRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method InsertOne not implemented") } func (UnimplementedModelBaseServiceV2Server) InsertMany(context.Context, *ModelServiceV2InsertManyRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method InsertMany not implemented") } func (UnimplementedModelBaseServiceV2Server) Count(context.Context, *ModelServiceV2CountRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Count not implemented") } func (UnimplementedModelBaseServiceV2Server) mustEmbedUnimplementedModelBaseServiceV2Server() {} // UnsafeModelBaseServiceV2Server may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ModelBaseServiceV2Server will // result in compilation errors. type UnsafeModelBaseServiceV2Server interface { mustEmbedUnimplementedModelBaseServiceV2Server() } func RegisterModelBaseServiceV2Server(s grpc.ServiceRegistrar, srv ModelBaseServiceV2Server) { s.RegisterService(&ModelBaseServiceV2_ServiceDesc, srv) } func _ModelBaseServiceV2_GetById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2GetByIdRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).GetById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_GetById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).GetById(ctx, req.(*ModelServiceV2GetByIdRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_GetOne_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2GetOneRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).GetOne(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_GetOne_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).GetOne(ctx, req.(*ModelServiceV2GetOneRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_GetMany_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2GetManyRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).GetMany(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_GetMany_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).GetMany(ctx, req.(*ModelServiceV2GetManyRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_DeleteById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2DeleteByIdRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).DeleteById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_DeleteById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).DeleteById(ctx, req.(*ModelServiceV2DeleteByIdRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_DeleteOne_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2DeleteOneRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).DeleteOne(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_DeleteOne_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).DeleteOne(ctx, req.(*ModelServiceV2DeleteOneRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_DeleteMany_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2DeleteManyRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).DeleteMany(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_DeleteMany_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).DeleteMany(ctx, req.(*ModelServiceV2DeleteManyRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_UpdateById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2UpdateByIdRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).UpdateById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_UpdateById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).UpdateById(ctx, req.(*ModelServiceV2UpdateByIdRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_UpdateOne_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2UpdateOneRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).UpdateOne(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_UpdateOne_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).UpdateOne(ctx, req.(*ModelServiceV2UpdateOneRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_UpdateMany_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2UpdateManyRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).UpdateMany(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_UpdateMany_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).UpdateMany(ctx, req.(*ModelServiceV2UpdateManyRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_ReplaceById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2ReplaceByIdRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).ReplaceById(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_ReplaceById_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).ReplaceById(ctx, req.(*ModelServiceV2ReplaceByIdRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_ReplaceOne_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2ReplaceOneRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).ReplaceOne(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_ReplaceOne_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).ReplaceOne(ctx, req.(*ModelServiceV2ReplaceOneRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_InsertOne_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2InsertOneRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).InsertOne(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_InsertOne_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).InsertOne(ctx, req.(*ModelServiceV2InsertOneRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_InsertMany_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2InsertManyRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).InsertMany(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_InsertMany_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).InsertMany(ctx, req.(*ModelServiceV2InsertManyRequest)) } return interceptor(ctx, in, info, handler) } func _ModelBaseServiceV2_Count_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ModelServiceV2CountRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelBaseServiceV2Server).Count(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelBaseServiceV2_Count_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelBaseServiceV2Server).Count(ctx, req.(*ModelServiceV2CountRequest)) } return interceptor(ctx, in, info, handler) } // ModelBaseServiceV2_ServiceDesc is the grpc.ServiceDesc for ModelBaseServiceV2 service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var ModelBaseServiceV2_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.ModelBaseServiceV2", HandlerType: (*ModelBaseServiceV2Server)(nil), Methods: []grpc.MethodDesc{ { MethodName: "GetById", Handler: _ModelBaseServiceV2_GetById_Handler, }, { MethodName: "GetOne", Handler: _ModelBaseServiceV2_GetOne_Handler, }, { MethodName: "GetMany", Handler: _ModelBaseServiceV2_GetMany_Handler, }, { MethodName: "DeleteById", Handler: _ModelBaseServiceV2_DeleteById_Handler, }, { MethodName: "DeleteOne", Handler: _ModelBaseServiceV2_DeleteOne_Handler, }, { MethodName: "DeleteMany", Handler: _ModelBaseServiceV2_DeleteMany_Handler, }, { MethodName: "UpdateById", Handler: _ModelBaseServiceV2_UpdateById_Handler, }, { MethodName: "UpdateOne", Handler: _ModelBaseServiceV2_UpdateOne_Handler, }, { MethodName: "UpdateMany", Handler: _ModelBaseServiceV2_UpdateMany_Handler, }, { MethodName: "ReplaceById", Handler: _ModelBaseServiceV2_ReplaceById_Handler, }, { MethodName: "ReplaceOne", Handler: _ModelBaseServiceV2_ReplaceOne_Handler, }, { MethodName: "InsertOne", Handler: _ModelBaseServiceV2_InsertOne_Handler, }, { MethodName: "InsertMany", Handler: _ModelBaseServiceV2_InsertMany_Handler, }, { MethodName: "Count", Handler: _ModelBaseServiceV2_Count_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "services/model_base_service_v2.proto", } ================================================ FILE: grpc/model_delegate.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/model_delegate.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) var File_services_model_delegate_proto protoreflect.FileDescriptor var file_services_model_delegate_proto_rawDesc = []byte{ 0x0a, 0x1d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x14, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x36, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x02, 0x44, 0x6f, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_services_model_delegate_proto_goTypes = []any{ (*Request)(nil), // 0: grpc.Request (*Response)(nil), // 1: grpc.Response } var file_services_model_delegate_proto_depIdxs = []int32{ 0, // 0: grpc.ModelDelegate.Do:input_type -> grpc.Request 1, // 1: grpc.ModelDelegate.Do:output_type -> grpc.Response 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_model_delegate_proto_init() } func file_services_model_delegate_proto_init() { if File_services_model_delegate_proto != nil { return } file_entity_request_proto_init() file_entity_response_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_model_delegate_proto_rawDesc, NumEnums: 0, NumMessages: 0, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_model_delegate_proto_goTypes, DependencyIndexes: file_services_model_delegate_proto_depIdxs, }.Build() File_services_model_delegate_proto = out.File file_services_model_delegate_proto_rawDesc = nil file_services_model_delegate_proto_goTypes = nil file_services_model_delegate_proto_depIdxs = nil } ================================================ FILE: grpc/model_delegate_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/model_delegate.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( ModelDelegate_Do_FullMethodName = "/grpc.ModelDelegate/Do" ) // ModelDelegateClient is the client API for ModelDelegate service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ModelDelegateClient interface { Do(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) } type modelDelegateClient struct { cc grpc.ClientConnInterface } func NewModelDelegateClient(cc grpc.ClientConnInterface) ModelDelegateClient { return &modelDelegateClient{cc} } func (c *modelDelegateClient) Do(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, ModelDelegate_Do_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // ModelDelegateServer is the server API for ModelDelegate service. // All implementations must embed UnimplementedModelDelegateServer // for forward compatibility type ModelDelegateServer interface { Do(context.Context, *Request) (*Response, error) mustEmbedUnimplementedModelDelegateServer() } // UnimplementedModelDelegateServer must be embedded to have forward compatible implementations. type UnimplementedModelDelegateServer struct { } func (UnimplementedModelDelegateServer) Do(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Do not implemented") } func (UnimplementedModelDelegateServer) mustEmbedUnimplementedModelDelegateServer() {} // UnsafeModelDelegateServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ModelDelegateServer will // result in compilation errors. type UnsafeModelDelegateServer interface { mustEmbedUnimplementedModelDelegateServer() } func RegisterModelDelegateServer(s grpc.ServiceRegistrar, srv ModelDelegateServer) { s.RegisterService(&ModelDelegate_ServiceDesc, srv) } func _ModelDelegate_Do_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ModelDelegateServer).Do(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: ModelDelegate_Do_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModelDelegateServer).Do(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } // ModelDelegate_ServiceDesc is the grpc.ServiceDesc for ModelDelegate service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var ModelDelegate_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.ModelDelegate", HandlerType: (*ModelDelegateServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Do", Handler: _ModelDelegate_Do_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "services/model_delegate.proto", } ================================================ FILE: grpc/model_service_v2_request.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/model_service_v2_request.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type ModelServiceV2GetByIdRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` } func (x *ModelServiceV2GetByIdRequest) Reset() { *x = ModelServiceV2GetByIdRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2GetByIdRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2GetByIdRequest) ProtoMessage() {} func (x *ModelServiceV2GetByIdRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2GetByIdRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2GetByIdRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{0} } func (x *ModelServiceV2GetByIdRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2GetByIdRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2GetByIdRequest) GetId() string { if x != nil { return x.Id } return "" } type ModelServiceV2GetOneRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` FindOptions []byte `protobuf:"bytes,4,opt,name=find_options,json=findOptions,proto3" json:"find_options,omitempty"` } func (x *ModelServiceV2GetOneRequest) Reset() { *x = ModelServiceV2GetOneRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2GetOneRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2GetOneRequest) ProtoMessage() {} func (x *ModelServiceV2GetOneRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2GetOneRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2GetOneRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{1} } func (x *ModelServiceV2GetOneRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2GetOneRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2GetOneRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } func (x *ModelServiceV2GetOneRequest) GetFindOptions() []byte { if x != nil { return x.FindOptions } return nil } type ModelServiceV2GetManyRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` FindOptions []byte `protobuf:"bytes,4,opt,name=find_options,json=findOptions,proto3" json:"find_options,omitempty"` } func (x *ModelServiceV2GetManyRequest) Reset() { *x = ModelServiceV2GetManyRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2GetManyRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2GetManyRequest) ProtoMessage() {} func (x *ModelServiceV2GetManyRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2GetManyRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2GetManyRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{2} } func (x *ModelServiceV2GetManyRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2GetManyRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2GetManyRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } func (x *ModelServiceV2GetManyRequest) GetFindOptions() []byte { if x != nil { return x.FindOptions } return nil } type ModelServiceV2DeleteByIdRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` } func (x *ModelServiceV2DeleteByIdRequest) Reset() { *x = ModelServiceV2DeleteByIdRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2DeleteByIdRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2DeleteByIdRequest) ProtoMessage() {} func (x *ModelServiceV2DeleteByIdRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2DeleteByIdRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2DeleteByIdRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{3} } func (x *ModelServiceV2DeleteByIdRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2DeleteByIdRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2DeleteByIdRequest) GetId() string { if x != nil { return x.Id } return "" } type ModelServiceV2DeleteOneRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` } func (x *ModelServiceV2DeleteOneRequest) Reset() { *x = ModelServiceV2DeleteOneRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2DeleteOneRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2DeleteOneRequest) ProtoMessage() {} func (x *ModelServiceV2DeleteOneRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2DeleteOneRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2DeleteOneRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{4} } func (x *ModelServiceV2DeleteOneRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2DeleteOneRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2DeleteOneRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } type ModelServiceV2DeleteManyRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` } func (x *ModelServiceV2DeleteManyRequest) Reset() { *x = ModelServiceV2DeleteManyRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2DeleteManyRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2DeleteManyRequest) ProtoMessage() {} func (x *ModelServiceV2DeleteManyRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2DeleteManyRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2DeleteManyRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{5} } func (x *ModelServiceV2DeleteManyRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2DeleteManyRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2DeleteManyRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } type ModelServiceV2UpdateByIdRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` Update []byte `protobuf:"bytes,4,opt,name=update,proto3" json:"update,omitempty"` } func (x *ModelServiceV2UpdateByIdRequest) Reset() { *x = ModelServiceV2UpdateByIdRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2UpdateByIdRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2UpdateByIdRequest) ProtoMessage() {} func (x *ModelServiceV2UpdateByIdRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2UpdateByIdRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2UpdateByIdRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{6} } func (x *ModelServiceV2UpdateByIdRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2UpdateByIdRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2UpdateByIdRequest) GetId() string { if x != nil { return x.Id } return "" } func (x *ModelServiceV2UpdateByIdRequest) GetUpdate() []byte { if x != nil { return x.Update } return nil } type ModelServiceV2UpdateOneRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` Update []byte `protobuf:"bytes,4,opt,name=update,proto3" json:"update,omitempty"` } func (x *ModelServiceV2UpdateOneRequest) Reset() { *x = ModelServiceV2UpdateOneRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2UpdateOneRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2UpdateOneRequest) ProtoMessage() {} func (x *ModelServiceV2UpdateOneRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2UpdateOneRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2UpdateOneRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{7} } func (x *ModelServiceV2UpdateOneRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2UpdateOneRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2UpdateOneRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } func (x *ModelServiceV2UpdateOneRequest) GetUpdate() []byte { if x != nil { return x.Update } return nil } type ModelServiceV2UpdateManyRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` Update []byte `protobuf:"bytes,4,opt,name=update,proto3" json:"update,omitempty"` } func (x *ModelServiceV2UpdateManyRequest) Reset() { *x = ModelServiceV2UpdateManyRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2UpdateManyRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2UpdateManyRequest) ProtoMessage() {} func (x *ModelServiceV2UpdateManyRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2UpdateManyRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2UpdateManyRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{8} } func (x *ModelServiceV2UpdateManyRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2UpdateManyRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2UpdateManyRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } func (x *ModelServiceV2UpdateManyRequest) GetUpdate() []byte { if x != nil { return x.Update } return nil } type ModelServiceV2ReplaceByIdRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` Model []byte `protobuf:"bytes,4,opt,name=model,proto3" json:"model,omitempty"` } func (x *ModelServiceV2ReplaceByIdRequest) Reset() { *x = ModelServiceV2ReplaceByIdRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2ReplaceByIdRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2ReplaceByIdRequest) ProtoMessage() {} func (x *ModelServiceV2ReplaceByIdRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2ReplaceByIdRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2ReplaceByIdRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{9} } func (x *ModelServiceV2ReplaceByIdRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2ReplaceByIdRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2ReplaceByIdRequest) GetId() string { if x != nil { return x.Id } return "" } func (x *ModelServiceV2ReplaceByIdRequest) GetModel() []byte { if x != nil { return x.Model } return nil } type ModelServiceV2ReplaceOneRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` Model []byte `protobuf:"bytes,4,opt,name=model,proto3" json:"model,omitempty"` } func (x *ModelServiceV2ReplaceOneRequest) Reset() { *x = ModelServiceV2ReplaceOneRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2ReplaceOneRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2ReplaceOneRequest) ProtoMessage() {} func (x *ModelServiceV2ReplaceOneRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2ReplaceOneRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2ReplaceOneRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{10} } func (x *ModelServiceV2ReplaceOneRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2ReplaceOneRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2ReplaceOneRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } func (x *ModelServiceV2ReplaceOneRequest) GetModel() []byte { if x != nil { return x.Model } return nil } type ModelServiceV2InsertOneRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Model []byte `protobuf:"bytes,3,opt,name=model,proto3" json:"model,omitempty"` } func (x *ModelServiceV2InsertOneRequest) Reset() { *x = ModelServiceV2InsertOneRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2InsertOneRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2InsertOneRequest) ProtoMessage() {} func (x *ModelServiceV2InsertOneRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2InsertOneRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2InsertOneRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{11} } func (x *ModelServiceV2InsertOneRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2InsertOneRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2InsertOneRequest) GetModel() []byte { if x != nil { return x.Model } return nil } type ModelServiceV2InsertManyRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Models []byte `protobuf:"bytes,3,opt,name=models,proto3" json:"models,omitempty"` } func (x *ModelServiceV2InsertManyRequest) Reset() { *x = ModelServiceV2InsertManyRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2InsertManyRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2InsertManyRequest) ProtoMessage() {} func (x *ModelServiceV2InsertManyRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2InsertManyRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2InsertManyRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{12} } func (x *ModelServiceV2InsertManyRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2InsertManyRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2InsertManyRequest) GetModels() []byte { if x != nil { return x.Models } return nil } type ModelServiceV2CountRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` ModelType string `protobuf:"bytes,2,opt,name=model_type,json=modelType,proto3" json:"model_type,omitempty"` Query []byte `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` } func (x *ModelServiceV2CountRequest) Reset() { *x = ModelServiceV2CountRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_model_service_v2_request_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *ModelServiceV2CountRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ModelServiceV2CountRequest) ProtoMessage() {} func (x *ModelServiceV2CountRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_model_service_v2_request_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ModelServiceV2CountRequest.ProtoReflect.Descriptor instead. func (*ModelServiceV2CountRequest) Descriptor() ([]byte, []int) { return file_entity_model_service_v2_request_proto_rawDescGZIP(), []int{13} } func (x *ModelServiceV2CountRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *ModelServiceV2CountRequest) GetModelType() string { if x != nil { return x.ModelType } return "" } func (x *ModelServiceV2CountRequest) GetQuery() []byte { if x != nil { return x.Query } return nil } var File_entity_model_service_v2_request_proto protoreflect.FileDescriptor var file_entity_model_service_v2_request_proto_rawDesc = []byte{ 0x0a, 0x25, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x68, 0x0a, 0x1c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x90, 0x01, 0x0a, 0x1b, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x1c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x6b, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x70, 0x0a, 0x1e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x83, 0x01, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x87, 0x01, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x70, 0x0a, 0x1e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x73, 0x0a, 0x1f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x22, 0x6c, 0x0a, 0x1a, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x32, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_model_service_v2_request_proto_rawDescOnce sync.Once file_entity_model_service_v2_request_proto_rawDescData = file_entity_model_service_v2_request_proto_rawDesc ) func file_entity_model_service_v2_request_proto_rawDescGZIP() []byte { file_entity_model_service_v2_request_proto_rawDescOnce.Do(func() { file_entity_model_service_v2_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_model_service_v2_request_proto_rawDescData) }) return file_entity_model_service_v2_request_proto_rawDescData } var file_entity_model_service_v2_request_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_entity_model_service_v2_request_proto_goTypes = []any{ (*ModelServiceV2GetByIdRequest)(nil), // 0: grpc.ModelServiceV2GetByIdRequest (*ModelServiceV2GetOneRequest)(nil), // 1: grpc.ModelServiceV2GetOneRequest (*ModelServiceV2GetManyRequest)(nil), // 2: grpc.ModelServiceV2GetManyRequest (*ModelServiceV2DeleteByIdRequest)(nil), // 3: grpc.ModelServiceV2DeleteByIdRequest (*ModelServiceV2DeleteOneRequest)(nil), // 4: grpc.ModelServiceV2DeleteOneRequest (*ModelServiceV2DeleteManyRequest)(nil), // 5: grpc.ModelServiceV2DeleteManyRequest (*ModelServiceV2UpdateByIdRequest)(nil), // 6: grpc.ModelServiceV2UpdateByIdRequest (*ModelServiceV2UpdateOneRequest)(nil), // 7: grpc.ModelServiceV2UpdateOneRequest (*ModelServiceV2UpdateManyRequest)(nil), // 8: grpc.ModelServiceV2UpdateManyRequest (*ModelServiceV2ReplaceByIdRequest)(nil), // 9: grpc.ModelServiceV2ReplaceByIdRequest (*ModelServiceV2ReplaceOneRequest)(nil), // 10: grpc.ModelServiceV2ReplaceOneRequest (*ModelServiceV2InsertOneRequest)(nil), // 11: grpc.ModelServiceV2InsertOneRequest (*ModelServiceV2InsertManyRequest)(nil), // 12: grpc.ModelServiceV2InsertManyRequest (*ModelServiceV2CountRequest)(nil), // 13: grpc.ModelServiceV2CountRequest } var file_entity_model_service_v2_request_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_model_service_v2_request_proto_init() } func file_entity_model_service_v2_request_proto_init() { if File_entity_model_service_v2_request_proto != nil { return } if !protoimpl.UnsafeEnabled { file_entity_model_service_v2_request_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2GetByIdRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2GetOneRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2GetManyRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2DeleteByIdRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2DeleteOneRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2DeleteManyRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2UpdateByIdRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2UpdateOneRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2UpdateManyRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2ReplaceByIdRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2ReplaceOneRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2InsertOneRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2InsertManyRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_entity_model_service_v2_request_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*ModelServiceV2CountRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_model_service_v2_request_proto_rawDesc, NumEnums: 0, NumMessages: 14, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_model_service_v2_request_proto_goTypes, DependencyIndexes: file_entity_model_service_v2_request_proto_depIdxs, MessageInfos: file_entity_model_service_v2_request_proto_msgTypes, }.Build() File_entity_model_service_v2_request_proto = out.File file_entity_model_service_v2_request_proto_rawDesc = nil file_entity_model_service_v2_request_proto_goTypes = nil file_entity_model_service_v2_request_proto_depIdxs = nil } ================================================ FILE: grpc/node.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: models/node.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type Node struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields XId string `protobuf:"bytes,1,opt,name=_id,json=Id,proto3" json:"_id,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` Port string `protobuf:"bytes,5,opt,name=port,proto3" json:"port,omitempty"` Mac string `protobuf:"bytes,6,opt,name=mac,proto3" json:"mac,omitempty"` Hostname string `protobuf:"bytes,7,opt,name=hostname,proto3" json:"hostname,omitempty"` Description string `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"` Key string `protobuf:"bytes,9,opt,name=key,proto3" json:"key,omitempty"` IsMaster bool `protobuf:"varint,11,opt,name=is_master,json=isMaster,proto3" json:"is_master,omitempty"` UpdateTs string `protobuf:"bytes,12,opt,name=update_ts,json=updateTs,proto3" json:"update_ts,omitempty"` CreateTs string `protobuf:"bytes,13,opt,name=create_ts,json=createTs,proto3" json:"create_ts,omitempty"` UpdateTsUnix int64 `protobuf:"varint,14,opt,name=update_ts_unix,json=updateTsUnix,proto3" json:"update_ts_unix,omitempty"` } func (x *Node) Reset() { *x = Node{} if protoimpl.UnsafeEnabled { mi := &file_models_node_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Node) String() string { return protoimpl.X.MessageStringOf(x) } func (*Node) ProtoMessage() {} func (x *Node) ProtoReflect() protoreflect.Message { mi := &file_models_node_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Node.ProtoReflect.Descriptor instead. func (*Node) Descriptor() ([]byte, []int) { return file_models_node_proto_rawDescGZIP(), []int{0} } func (x *Node) GetXId() string { if x != nil { return x.XId } return "" } func (x *Node) GetName() string { if x != nil { return x.Name } return "" } func (x *Node) GetIp() string { if x != nil { return x.Ip } return "" } func (x *Node) GetPort() string { if x != nil { return x.Port } return "" } func (x *Node) GetMac() string { if x != nil { return x.Mac } return "" } func (x *Node) GetHostname() string { if x != nil { return x.Hostname } return "" } func (x *Node) GetDescription() string { if x != nil { return x.Description } return "" } func (x *Node) GetKey() string { if x != nil { return x.Key } return "" } func (x *Node) GetIsMaster() bool { if x != nil { return x.IsMaster } return false } func (x *Node) GetUpdateTs() string { if x != nil { return x.UpdateTs } return "" } func (x *Node) GetCreateTs() string { if x != nil { return x.CreateTs } return "" } func (x *Node) GetUpdateTsUnix() int64 { if x != nil { return x.UpdateTsUnix } return 0 } var File_models_node_proto protoreflect.FileDescriptor var file_models_node_proto_rawDesc = []byte{ 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0xae, 0x02, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x61, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x55, 0x6e, 0x69, 0x78, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_models_node_proto_rawDescOnce sync.Once file_models_node_proto_rawDescData = file_models_node_proto_rawDesc ) func file_models_node_proto_rawDescGZIP() []byte { file_models_node_proto_rawDescOnce.Do(func() { file_models_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_node_proto_rawDescData) }) return file_models_node_proto_rawDescData } var file_models_node_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_models_node_proto_goTypes = []any{ (*Node)(nil), // 0: grpc.Node } var file_models_node_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_models_node_proto_init() } func file_models_node_proto_init() { if File_models_node_proto != nil { return } if !protoimpl.UnsafeEnabled { file_models_node_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Node); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_models_node_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_models_node_proto_goTypes, DependencyIndexes: file_models_node_proto_depIdxs, MessageInfos: file_models_node_proto_msgTypes, }.Build() File_models_node_proto = out.File file_models_node_proto_rawDesc = nil file_models_node_proto_goTypes = nil file_models_node_proto_depIdxs = nil } ================================================ FILE: grpc/node_info.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/node_info.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type NodeInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` IsMaster bool `protobuf:"varint,2,opt,name=is_master,json=isMaster,proto3" json:"is_master,omitempty"` } func (x *NodeInfo) Reset() { *x = NodeInfo{} if protoimpl.UnsafeEnabled { mi := &file_entity_node_info_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *NodeInfo) String() string { return protoimpl.X.MessageStringOf(x) } func (*NodeInfo) ProtoMessage() {} func (x *NodeInfo) ProtoReflect() protoreflect.Message { mi := &file_entity_node_info_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use NodeInfo.ProtoReflect.Descriptor instead. func (*NodeInfo) Descriptor() ([]byte, []int) { return file_entity_node_info_proto_rawDescGZIP(), []int{0} } func (x *NodeInfo) GetKey() string { if x != nil { return x.Key } return "" } func (x *NodeInfo) GetIsMaster() bool { if x != nil { return x.IsMaster } return false } var File_entity_node_info_proto protoreflect.FileDescriptor var file_entity_node_info_proto_rawDesc = []byte{ 0x0a, 0x16, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x39, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_node_info_proto_rawDescOnce sync.Once file_entity_node_info_proto_rawDescData = file_entity_node_info_proto_rawDesc ) func file_entity_node_info_proto_rawDescGZIP() []byte { file_entity_node_info_proto_rawDescOnce.Do(func() { file_entity_node_info_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_node_info_proto_rawDescData) }) return file_entity_node_info_proto_rawDescData } var file_entity_node_info_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_node_info_proto_goTypes = []any{ (*NodeInfo)(nil), // 0: grpc.NodeInfo } var file_entity_node_info_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_node_info_proto_init() } func file_entity_node_info_proto_init() { if File_entity_node_info_proto != nil { return } if !protoimpl.UnsafeEnabled { file_entity_node_info_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*NodeInfo); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_node_info_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_node_info_proto_goTypes, DependencyIndexes: file_entity_node_info_proto_depIdxs, MessageInfos: file_entity_node_info_proto_msgTypes, }.Build() File_entity_node_info_proto = out.File file_entity_node_info_proto_rawDesc = nil file_entity_node_info_proto_goTypes = nil file_entity_node_info_proto_depIdxs = nil } ================================================ FILE: grpc/node_service.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/node_service.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type NodeServiceRegisterRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` IsMaster bool `protobuf:"varint,3,opt,name=isMaster,proto3" json:"isMaster,omitempty"` AuthKey string `protobuf:"bytes,4,opt,name=authKey,proto3" json:"authKey,omitempty"` MaxRunners int32 `protobuf:"varint,5,opt,name=maxRunners,proto3" json:"maxRunners,omitempty"` } func (x *NodeServiceRegisterRequest) Reset() { *x = NodeServiceRegisterRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_node_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *NodeServiceRegisterRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*NodeServiceRegisterRequest) ProtoMessage() {} func (x *NodeServiceRegisterRequest) ProtoReflect() protoreflect.Message { mi := &file_services_node_service_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use NodeServiceRegisterRequest.ProtoReflect.Descriptor instead. func (*NodeServiceRegisterRequest) Descriptor() ([]byte, []int) { return file_services_node_service_proto_rawDescGZIP(), []int{0} } func (x *NodeServiceRegisterRequest) GetKey() string { if x != nil { return x.Key } return "" } func (x *NodeServiceRegisterRequest) GetName() string { if x != nil { return x.Name } return "" } func (x *NodeServiceRegisterRequest) GetIsMaster() bool { if x != nil { return x.IsMaster } return false } func (x *NodeServiceRegisterRequest) GetAuthKey() string { if x != nil { return x.AuthKey } return "" } func (x *NodeServiceRegisterRequest) GetMaxRunners() int32 { if x != nil { return x.MaxRunners } return 0 } type NodeServiceSendHeartbeatRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` } func (x *NodeServiceSendHeartbeatRequest) Reset() { *x = NodeServiceSendHeartbeatRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_node_service_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *NodeServiceSendHeartbeatRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*NodeServiceSendHeartbeatRequest) ProtoMessage() {} func (x *NodeServiceSendHeartbeatRequest) ProtoReflect() protoreflect.Message { mi := &file_services_node_service_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use NodeServiceSendHeartbeatRequest.ProtoReflect.Descriptor instead. func (*NodeServiceSendHeartbeatRequest) Descriptor() ([]byte, []int) { return file_services_node_service_proto_rawDescGZIP(), []int{1} } func (x *NodeServiceSendHeartbeatRequest) GetKey() string { if x != nil { return x.Key } return "" } var File_services_node_service_proto protoreflect.FileDescriptor var file_services_node_service_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x14, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x98, 0x01, 0x0a, 0x1a, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x33, 0x0a, 0x1f, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x32, 0xfc, 0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2e, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_services_node_service_proto_rawDescOnce sync.Once file_services_node_service_proto_rawDescData = file_services_node_service_proto_rawDesc ) func file_services_node_service_proto_rawDescGZIP() []byte { file_services_node_service_proto_rawDescOnce.Do(func() { file_services_node_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_services_node_service_proto_rawDescData) }) return file_services_node_service_proto_rawDescData } var file_services_node_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_services_node_service_proto_goTypes = []any{ (*NodeServiceRegisterRequest)(nil), // 0: grpc.NodeServiceRegisterRequest (*NodeServiceSendHeartbeatRequest)(nil), // 1: grpc.NodeServiceSendHeartbeatRequest (*Request)(nil), // 2: grpc.Request (*Response)(nil), // 3: grpc.Response (*StreamMessage)(nil), // 4: grpc.StreamMessage } var file_services_node_service_proto_depIdxs = []int32{ 0, // 0: grpc.NodeService.Register:input_type -> grpc.NodeServiceRegisterRequest 1, // 1: grpc.NodeService.SendHeartbeat:input_type -> grpc.NodeServiceSendHeartbeatRequest 2, // 2: grpc.NodeService.Subscribe:input_type -> grpc.Request 2, // 3: grpc.NodeService.Unsubscribe:input_type -> grpc.Request 3, // 4: grpc.NodeService.Register:output_type -> grpc.Response 3, // 5: grpc.NodeService.SendHeartbeat:output_type -> grpc.Response 4, // 6: grpc.NodeService.Subscribe:output_type -> grpc.StreamMessage 3, // 7: grpc.NodeService.Unsubscribe:output_type -> grpc.Response 4, // [4:8] is the sub-list for method output_type 0, // [0:4] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_node_service_proto_init() } func file_services_node_service_proto_init() { if File_services_node_service_proto != nil { return } file_entity_request_proto_init() file_entity_response_proto_init() file_entity_stream_message_proto_init() if !protoimpl.UnsafeEnabled { file_services_node_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*NodeServiceRegisterRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_services_node_service_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*NodeServiceSendHeartbeatRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_node_service_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_node_service_proto_goTypes, DependencyIndexes: file_services_node_service_proto_depIdxs, MessageInfos: file_services_node_service_proto_msgTypes, }.Build() File_services_node_service_proto = out.File file_services_node_service_proto_rawDesc = nil file_services_node_service_proto_goTypes = nil file_services_node_service_proto_depIdxs = nil } ================================================ FILE: grpc/node_service_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/node_service.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( NodeService_Register_FullMethodName = "/grpc.NodeService/Register" NodeService_SendHeartbeat_FullMethodName = "/grpc.NodeService/SendHeartbeat" NodeService_Subscribe_FullMethodName = "/grpc.NodeService/Subscribe" NodeService_Unsubscribe_FullMethodName = "/grpc.NodeService/Unsubscribe" ) // NodeServiceClient is the client API for NodeService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type NodeServiceClient interface { Register(ctx context.Context, in *NodeServiceRegisterRequest, opts ...grpc.CallOption) (*Response, error) SendHeartbeat(ctx context.Context, in *NodeServiceSendHeartbeatRequest, opts ...grpc.CallOption) (*Response, error) Subscribe(ctx context.Context, in *Request, opts ...grpc.CallOption) (NodeService_SubscribeClient, error) Unsubscribe(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) } type nodeServiceClient struct { cc grpc.ClientConnInterface } func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient { return &nodeServiceClient{cc} } func (c *nodeServiceClient) Register(ctx context.Context, in *NodeServiceRegisterRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, NodeService_Register_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *nodeServiceClient) SendHeartbeat(ctx context.Context, in *NodeServiceSendHeartbeatRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, NodeService_SendHeartbeat_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *nodeServiceClient) Subscribe(ctx context.Context, in *Request, opts ...grpc.CallOption) (NodeService_SubscribeClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &NodeService_ServiceDesc.Streams[0], NodeService_Subscribe_FullMethodName, cOpts...) if err != nil { return nil, err } x := &nodeServiceSubscribeClient{ClientStream: stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } if err := x.ClientStream.CloseSend(); err != nil { return nil, err } return x, nil } type NodeService_SubscribeClient interface { Recv() (*StreamMessage, error) grpc.ClientStream } type nodeServiceSubscribeClient struct { grpc.ClientStream } func (x *nodeServiceSubscribeClient) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *nodeServiceClient) Unsubscribe(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, NodeService_Unsubscribe_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // NodeServiceServer is the server API for NodeService service. // All implementations must embed UnimplementedNodeServiceServer // for forward compatibility type NodeServiceServer interface { Register(context.Context, *NodeServiceRegisterRequest) (*Response, error) SendHeartbeat(context.Context, *NodeServiceSendHeartbeatRequest) (*Response, error) Subscribe(*Request, NodeService_SubscribeServer) error Unsubscribe(context.Context, *Request) (*Response, error) mustEmbedUnimplementedNodeServiceServer() } // UnimplementedNodeServiceServer must be embedded to have forward compatible implementations. type UnimplementedNodeServiceServer struct { } func (UnimplementedNodeServiceServer) Register(context.Context, *NodeServiceRegisterRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") } func (UnimplementedNodeServiceServer) SendHeartbeat(context.Context, *NodeServiceSendHeartbeatRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method SendHeartbeat not implemented") } func (UnimplementedNodeServiceServer) Subscribe(*Request, NodeService_SubscribeServer) error { return status.Errorf(codes.Unimplemented, "method Subscribe not implemented") } func (UnimplementedNodeServiceServer) Unsubscribe(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Unsubscribe not implemented") } func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {} // UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to NodeServiceServer will // result in compilation errors. type UnsafeNodeServiceServer interface { mustEmbedUnimplementedNodeServiceServer() } func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) { s.RegisterService(&NodeService_ServiceDesc, srv) } func _NodeService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(NodeServiceRegisterRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(NodeServiceServer).Register(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: NodeService_Register_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(NodeServiceServer).Register(ctx, req.(*NodeServiceRegisterRequest)) } return interceptor(ctx, in, info, handler) } func _NodeService_SendHeartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(NodeServiceSendHeartbeatRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(NodeServiceServer).SendHeartbeat(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: NodeService_SendHeartbeat_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(NodeServiceServer).SendHeartbeat(ctx, req.(*NodeServiceSendHeartbeatRequest)) } return interceptor(ctx, in, info, handler) } func _NodeService_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(Request) if err := stream.RecvMsg(m); err != nil { return err } return srv.(NodeServiceServer).Subscribe(m, &nodeServiceSubscribeServer{ServerStream: stream}) } type NodeService_SubscribeServer interface { Send(*StreamMessage) error grpc.ServerStream } type nodeServiceSubscribeServer struct { grpc.ServerStream } func (x *nodeServiceSubscribeServer) Send(m *StreamMessage) error { return x.ServerStream.SendMsg(m) } func _NodeService_Unsubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(NodeServiceServer).Unsubscribe(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: NodeService_Unsubscribe_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(NodeServiceServer).Unsubscribe(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } // NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var NodeService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.NodeService", HandlerType: (*NodeServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Register", Handler: _NodeService_Register_Handler, }, { MethodName: "SendHeartbeat", Handler: _NodeService_SendHeartbeat_Handler, }, { MethodName: "Unsubscribe", Handler: _NodeService_Unsubscribe_Handler, }, }, Streams: []grpc.StreamDesc{ { StreamName: "Subscribe", Handler: _NodeService_Subscribe_Handler, ServerStreams: true, }, }, Metadata: "services/node_service.proto", } ================================================ FILE: grpc/plugin_request.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/plugin_request.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type PluginRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` NodeKey string `protobuf:"bytes,2,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } func (x *PluginRequest) Reset() { *x = PluginRequest{} if protoimpl.UnsafeEnabled { mi := &file_entity_plugin_request_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *PluginRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*PluginRequest) ProtoMessage() {} func (x *PluginRequest) ProtoReflect() protoreflect.Message { mi := &file_entity_plugin_request_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use PluginRequest.ProtoReflect.Descriptor instead. func (*PluginRequest) Descriptor() ([]byte, []int) { return file_entity_plugin_request_proto_rawDescGZIP(), []int{0} } func (x *PluginRequest) GetName() string { if x != nil { return x.Name } return "" } func (x *PluginRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *PluginRequest) GetData() []byte { if x != nil { return x.Data } return nil } var File_entity_plugin_request_proto protoreflect.FileDescriptor var file_entity_plugin_request_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x52, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_plugin_request_proto_rawDescOnce sync.Once file_entity_plugin_request_proto_rawDescData = file_entity_plugin_request_proto_rawDesc ) func file_entity_plugin_request_proto_rawDescGZIP() []byte { file_entity_plugin_request_proto_rawDescOnce.Do(func() { file_entity_plugin_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_plugin_request_proto_rawDescData) }) return file_entity_plugin_request_proto_rawDescData } var file_entity_plugin_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_plugin_request_proto_goTypes = []any{ (*PluginRequest)(nil), // 0: grpc.PluginRequest } var file_entity_plugin_request_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_plugin_request_proto_init() } func file_entity_plugin_request_proto_init() { if File_entity_plugin_request_proto != nil { return } if !protoimpl.UnsafeEnabled { file_entity_plugin_request_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*PluginRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_plugin_request_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_plugin_request_proto_goTypes, DependencyIndexes: file_entity_plugin_request_proto_depIdxs, MessageInfos: file_entity_plugin_request_proto_msgTypes, }.Build() File_entity_plugin_request_proto = out.File file_entity_plugin_request_proto_rawDesc = nil file_entity_plugin_request_proto_goTypes = nil file_entity_plugin_request_proto_depIdxs = nil } ================================================ FILE: grpc/plugin_service.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/plugin_service.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) var File_services_plugin_service_proto protoreflect.FileDescriptor var file_services_plugin_service_proto_rawDesc = []byte{ 0x0a, 0x1d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xb5, 0x01, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x36, 0x0a, 0x04, 0x50, 0x6f, 0x6c, 0x6c, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_services_plugin_service_proto_goTypes = []any{ (*PluginRequest)(nil), // 0: grpc.PluginRequest (*StreamMessage)(nil), // 1: grpc.StreamMessage (*Response)(nil), // 2: grpc.Response } var file_services_plugin_service_proto_depIdxs = []int32{ 0, // 0: grpc.PluginService.Register:input_type -> grpc.PluginRequest 0, // 1: grpc.PluginService.Subscribe:input_type -> grpc.PluginRequest 1, // 2: grpc.PluginService.Poll:input_type -> grpc.StreamMessage 2, // 3: grpc.PluginService.Register:output_type -> grpc.Response 1, // 4: grpc.PluginService.Subscribe:output_type -> grpc.StreamMessage 1, // 5: grpc.PluginService.Poll:output_type -> grpc.StreamMessage 3, // [3:6] is the sub-list for method output_type 0, // [0:3] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_plugin_service_proto_init() } func file_services_plugin_service_proto_init() { if File_services_plugin_service_proto != nil { return } file_entity_plugin_request_proto_init() file_entity_response_proto_init() file_entity_stream_message_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_plugin_service_proto_rawDesc, NumEnums: 0, NumMessages: 0, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_plugin_service_proto_goTypes, DependencyIndexes: file_services_plugin_service_proto_depIdxs, }.Build() File_services_plugin_service_proto = out.File file_services_plugin_service_proto_rawDesc = nil file_services_plugin_service_proto_goTypes = nil file_services_plugin_service_proto_depIdxs = nil } ================================================ FILE: grpc/plugin_service_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/plugin_service.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( PluginService_Register_FullMethodName = "/grpc.PluginService/Register" PluginService_Subscribe_FullMethodName = "/grpc.PluginService/Subscribe" PluginService_Poll_FullMethodName = "/grpc.PluginService/Poll" ) // PluginServiceClient is the client API for PluginService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type PluginServiceClient interface { Register(ctx context.Context, in *PluginRequest, opts ...grpc.CallOption) (*Response, error) Subscribe(ctx context.Context, in *PluginRequest, opts ...grpc.CallOption) (PluginService_SubscribeClient, error) Poll(ctx context.Context, opts ...grpc.CallOption) (PluginService_PollClient, error) } type pluginServiceClient struct { cc grpc.ClientConnInterface } func NewPluginServiceClient(cc grpc.ClientConnInterface) PluginServiceClient { return &pluginServiceClient{cc} } func (c *pluginServiceClient) Register(ctx context.Context, in *PluginRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, PluginService_Register_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *pluginServiceClient) Subscribe(ctx context.Context, in *PluginRequest, opts ...grpc.CallOption) (PluginService_SubscribeClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &PluginService_ServiceDesc.Streams[0], PluginService_Subscribe_FullMethodName, cOpts...) if err != nil { return nil, err } x := &pluginServiceSubscribeClient{ClientStream: stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } if err := x.ClientStream.CloseSend(); err != nil { return nil, err } return x, nil } type PluginService_SubscribeClient interface { Recv() (*StreamMessage, error) grpc.ClientStream } type pluginServiceSubscribeClient struct { grpc.ClientStream } func (x *pluginServiceSubscribeClient) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *pluginServiceClient) Poll(ctx context.Context, opts ...grpc.CallOption) (PluginService_PollClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &PluginService_ServiceDesc.Streams[1], PluginService_Poll_FullMethodName, cOpts...) if err != nil { return nil, err } x := &pluginServicePollClient{ClientStream: stream} return x, nil } type PluginService_PollClient interface { Send(*StreamMessage) error Recv() (*StreamMessage, error) grpc.ClientStream } type pluginServicePollClient struct { grpc.ClientStream } func (x *pluginServicePollClient) Send(m *StreamMessage) error { return x.ClientStream.SendMsg(m) } func (x *pluginServicePollClient) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // PluginServiceServer is the server API for PluginService service. // All implementations must embed UnimplementedPluginServiceServer // for forward compatibility type PluginServiceServer interface { Register(context.Context, *PluginRequest) (*Response, error) Subscribe(*PluginRequest, PluginService_SubscribeServer) error Poll(PluginService_PollServer) error mustEmbedUnimplementedPluginServiceServer() } // UnimplementedPluginServiceServer must be embedded to have forward compatible implementations. type UnimplementedPluginServiceServer struct { } func (UnimplementedPluginServiceServer) Register(context.Context, *PluginRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") } func (UnimplementedPluginServiceServer) Subscribe(*PluginRequest, PluginService_SubscribeServer) error { return status.Errorf(codes.Unimplemented, "method Subscribe not implemented") } func (UnimplementedPluginServiceServer) Poll(PluginService_PollServer) error { return status.Errorf(codes.Unimplemented, "method Poll not implemented") } func (UnimplementedPluginServiceServer) mustEmbedUnimplementedPluginServiceServer() {} // UnsafePluginServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to PluginServiceServer will // result in compilation errors. type UnsafePluginServiceServer interface { mustEmbedUnimplementedPluginServiceServer() } func RegisterPluginServiceServer(s grpc.ServiceRegistrar, srv PluginServiceServer) { s.RegisterService(&PluginService_ServiceDesc, srv) } func _PluginService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(PluginRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(PluginServiceServer).Register(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: PluginService_Register_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(PluginServiceServer).Register(ctx, req.(*PluginRequest)) } return interceptor(ctx, in, info, handler) } func _PluginService_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(PluginRequest) if err := stream.RecvMsg(m); err != nil { return err } return srv.(PluginServiceServer).Subscribe(m, &pluginServiceSubscribeServer{ServerStream: stream}) } type PluginService_SubscribeServer interface { Send(*StreamMessage) error grpc.ServerStream } type pluginServiceSubscribeServer struct { grpc.ServerStream } func (x *pluginServiceSubscribeServer) Send(m *StreamMessage) error { return x.ServerStream.SendMsg(m) } func _PluginService_Poll_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(PluginServiceServer).Poll(&pluginServicePollServer{ServerStream: stream}) } type PluginService_PollServer interface { Send(*StreamMessage) error Recv() (*StreamMessage, error) grpc.ServerStream } type pluginServicePollServer struct { grpc.ServerStream } func (x *pluginServicePollServer) Send(m *StreamMessage) error { return x.ServerStream.SendMsg(m) } func (x *pluginServicePollServer) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // PluginService_ServiceDesc is the grpc.ServiceDesc for PluginService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var PluginService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.PluginService", HandlerType: (*PluginServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Register", Handler: _PluginService_Register_Handler, }, }, Streams: []grpc.StreamDesc{ { StreamName: "Subscribe", Handler: _PluginService_Subscribe_Handler, ServerStreams: true, }, { StreamName: "Poll", Handler: _PluginService_Poll_Handler, ServerStreams: true, ClientStreams: true, }, }, Metadata: "services/plugin_service.proto", } ================================================ FILE: grpc/proto/entity/model_service_v2_request.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message ModelServiceV2GetByIdRequest { string node_key = 1; string model_type = 2; string id = 3; } message ModelServiceV2GetOneRequest { string node_key = 1; string model_type = 2; bytes query = 3; bytes find_options = 4; } message ModelServiceV2GetManyRequest { string node_key = 1; string model_type = 2; bytes query = 3; bytes find_options = 4; } message ModelServiceV2DeleteByIdRequest { string node_key = 1; string model_type = 2; string id = 3; } message ModelServiceV2DeleteOneRequest { string node_key = 1; string model_type = 2; bytes query = 3; } message ModelServiceV2DeleteManyRequest { string node_key = 1; string model_type = 2; bytes query = 3; } message ModelServiceV2UpdateByIdRequest { string node_key = 1; string model_type = 2; string id = 3; bytes update = 4; } message ModelServiceV2UpdateOneRequest { string node_key = 1; string model_type = 2; bytes query = 3; bytes update = 4; } message ModelServiceV2UpdateManyRequest { string node_key = 1; string model_type = 2; bytes query = 3; bytes update = 4; } message ModelServiceV2ReplaceByIdRequest { string node_key = 1; string model_type = 2; string id = 3; bytes model = 4; } message ModelServiceV2ReplaceOneRequest { string node_key = 1; string model_type = 2; bytes query = 3; bytes model = 4; } message ModelServiceV2InsertOneRequest { string node_key = 1; string model_type = 2; bytes model = 3; } message ModelServiceV2InsertManyRequest { string node_key = 1; string model_type = 2; bytes models = 3; } message ModelServiceV2CountRequest { string node_key = 1; string model_type = 2; bytes query = 3; } ================================================ FILE: grpc/proto/entity/node_info.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message NodeInfo { string key = 1; bool is_master = 2; } ================================================ FILE: grpc/proto/entity/plugin_request.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message PluginRequest { string name = 1; string node_key = 2; bytes data = 3; } ================================================ FILE: grpc/proto/entity/request.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message Request { string node_key = 1; bytes data = 2; } ================================================ FILE: grpc/proto/entity/response.proto ================================================ syntax = "proto3"; import "entity/response_code.proto"; package grpc; option go_package = ".;grpc"; message Response { ResponseCode code = 1; string message = 2; bytes data = 3; string error = 4; int64 total = 5; } ================================================ FILE: grpc/proto/entity/response_code.proto ================================================ syntax = "proto3"; option go_package = ".;grpc"; enum ResponseCode { OK = 0; ERROR = 1; } ================================================ FILE: grpc/proto/entity/stream_message.proto ================================================ syntax = "proto3"; import "entity/stream_message_code.proto"; package grpc; option go_package = ".;grpc"; message StreamMessage { StreamMessageCode code = 1; string node_key = 2; string key = 3; string from = 4; string to = 5; bytes data = 6; string error = 7; } ================================================ FILE: grpc/proto/entity/stream_message_code.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; enum StreamMessageCode { // ping worker nodes to check their health PING = 0; // ask worker node(s) to run task with given id RUN_TASK = 1; // ask worker node(s) to cancel task with given id CANCEL_TASK = 2; // insert data INSERT_DATA = 3; // insert logs INSERT_LOGS = 4; // send event SEND_EVENT = 5; // install plugin INSTALL_PLUGIN = 6; // uninstall plugin UNINSTALL_PLUGIN = 7; // start plugin START_PLUGIN = 8; // stop plugin STOP_PLUGIN = 9; // connect CONNECT = 10; // disconnect DISCONNECT = 11; // send SEND = 12; } ================================================ FILE: grpc/proto/entity/stream_message_data_task.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message StreamMessageDataTask { string task_id = 1; string data = 2; } ================================================ FILE: grpc/proto/models/node.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message Node { string _id = 1; string name = 2; string ip = 3; string port = 5; string mac = 6; string hostname = 7; string description = 8; string key = 9; bool is_master = 11; string update_ts = 12; string create_ts = 13; int64 update_ts_unix = 14; } ================================================ FILE: grpc/proto/models/task.proto ================================================ syntax = "proto3"; package grpc; option go_package = ".;grpc"; message Task { string _id = 1; string spider_id = 2; string status = 5; string node_id = 6; string cmd = 8; string param = 9; string error = 10; int32 pid = 16; string run_type = 17; string schedule_id = 18; string type = 19; } ================================================ FILE: grpc/proto/services/dependencies_service_v2.proto ================================================ syntax = "proto3"; import "entity/response.proto"; package grpc; option go_package = ".;grpc"; message Dependency { string name = 1; string version = 2; } message DependenciesServiceV2ConnectRequest { string node_key = 1; } enum DependenciesServiceV2Code { SYNC = 0; INSTALL = 1; UNINSTALL = 2; } message DependenciesServiceV2ConnectResponse { DependenciesServiceV2Code code = 1; string task_id = 2; string lang = 3; string proxy = 4; repeated Dependency dependencies = 5; } message DependenciesServiceV2SyncRequest { string node_key = 1; string lang = 2; repeated Dependency dependencies = 3; } message DependenciesServiceV2UpdateTaskLogRequest { string task_id = 1; repeated string log_lines = 2; } service DependenciesServiceV2 { rpc Connect(DependenciesServiceV2ConnectRequest) returns (stream DependenciesServiceV2ConnectResponse){}; rpc Sync(DependenciesServiceV2SyncRequest) returns (Response){}; rpc UpdateTaskLog(stream DependenciesServiceV2UpdateTaskLogRequest) returns (Response){}; } ================================================ FILE: grpc/proto/services/message_service.proto ================================================ syntax = "proto3"; import "entity/stream_message.proto"; package grpc; option go_package = ".;grpc"; service MessageService { rpc Connect(stream StreamMessage) returns (stream StreamMessage){}; } ================================================ FILE: grpc/proto/services/metrics_service_v2.proto ================================================ syntax = "proto3"; import "entity/response.proto"; package grpc; option go_package = ".;grpc"; message MetricsServiceV2SendRequest { string type = 1; string node_key = 2; int64 timestamp = 3; float cpu_usage_percent = 4; uint64 total_memory = 5; uint64 available_memory = 6; uint64 used_memory = 7; float used_memory_percent = 8; uint64 total_disk = 9; uint64 available_disk = 10; uint64 used_disk = 11; float used_disk_percent = 12; float disk_read_bytes_rate = 15; float disk_write_bytes_rate = 16; float network_bytes_sent_rate = 17; float network_bytes_recv_rate = 18; } service MetricsServiceV2 { rpc Send(MetricsServiceV2SendRequest) returns (Response){}; } ================================================ FILE: grpc/proto/services/model_base_service.proto ================================================ syntax = "proto3"; import "entity/request.proto"; import "entity/response.proto"; package grpc; option go_package = ".;grpc"; service ModelBaseService { rpc GetById(Request) returns (Response){}; rpc Get(Request) returns (Response){}; rpc GetList(Request) returns (Response){}; rpc DeleteById(Request) returns (Response){}; rpc Delete(Request) returns (Response){}; rpc DeleteList(Request) returns (Response){}; rpc ForceDeleteList(Request) returns (Response){}; rpc UpdateById(Request) returns (Response){}; rpc Update(Request) returns (Response){}; rpc UpdateDoc(Request) returns (Response){}; rpc Insert(Request) returns (Response){}; rpc Count(Request) returns (Response){}; } ================================================ FILE: grpc/proto/services/model_base_service_v2.proto ================================================ syntax = "proto3"; import "entity/model_service_v2_request.proto"; import "entity/response.proto"; package grpc; option go_package = ".;grpc"; service ModelBaseServiceV2 { rpc GetById(ModelServiceV2GetByIdRequest) returns (Response){}; rpc GetOne(ModelServiceV2GetOneRequest) returns (Response){}; rpc GetMany(ModelServiceV2GetManyRequest) returns (Response){}; rpc DeleteById(ModelServiceV2DeleteByIdRequest) returns (Response){}; rpc DeleteOne(ModelServiceV2DeleteOneRequest) returns (Response){}; rpc DeleteMany(ModelServiceV2DeleteManyRequest) returns (Response){}; rpc UpdateById(ModelServiceV2UpdateByIdRequest) returns (Response){}; rpc UpdateOne(ModelServiceV2UpdateOneRequest) returns (Response){}; rpc UpdateMany(ModelServiceV2UpdateManyRequest) returns (Response){}; rpc ReplaceById(ModelServiceV2ReplaceByIdRequest) returns (Response){}; rpc ReplaceOne(ModelServiceV2ReplaceOneRequest) returns (Response){}; rpc InsertOne(ModelServiceV2InsertOneRequest) returns (Response){}; rpc InsertMany(ModelServiceV2InsertManyRequest) returns (Response){}; rpc Count(ModelServiceV2CountRequest) returns (Response){}; } ================================================ FILE: grpc/proto/services/model_delegate.proto ================================================ syntax = "proto3"; import "entity/request.proto"; import "entity/response.proto"; package grpc; option go_package = ".;grpc"; service ModelDelegate { rpc Do(Request) returns (Response){}; } ================================================ FILE: grpc/proto/services/node_service.proto ================================================ syntax = "proto3"; import "entity/request.proto"; import "entity/response.proto"; import "entity/stream_message.proto"; package grpc; option go_package = ".;grpc"; message NodeServiceRegisterRequest { string key = 1; string name = 2; bool isMaster = 3; string authKey = 4; int32 maxRunners = 5; } message NodeServiceSendHeartbeatRequest { string key = 1; } service NodeService { rpc Register(NodeServiceRegisterRequest) returns (Response){}; rpc SendHeartbeat(NodeServiceSendHeartbeatRequest) returns (Response){}; rpc Subscribe(Request) returns (stream StreamMessage){}; rpc Unsubscribe(Request) returns (Response){}; } ================================================ FILE: grpc/proto/services/plugin_service.proto ================================================ syntax = "proto3"; import "entity/plugin_request.proto"; import "entity/response.proto"; import "entity/stream_message.proto"; package grpc; option go_package = ".;grpc"; service PluginService { rpc Register(PluginRequest) returns (Response){}; rpc Subscribe(PluginRequest) returns (stream StreamMessage){}; rpc Poll(stream StreamMessage) returns (stream StreamMessage){}; } ================================================ FILE: grpc/proto/services/task_service.proto ================================================ syntax = "proto3"; import "entity/request.proto"; import "entity/response.proto"; import "entity/stream_message.proto"; package grpc; option go_package = ".;grpc"; message TaskServiceSendNotificationRequest { string node_key = 1; string task_id = 2; } service TaskService { rpc Subscribe(stream StreamMessage) returns (Response){}; rpc Fetch(Request) returns (Response){}; rpc SendNotification(TaskServiceSendNotificationRequest) returns (Response){}; } ================================================ FILE: grpc/request.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/request.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type Request struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } func (x *Request) Reset() { *x = Request{} if protoimpl.UnsafeEnabled { mi := &file_entity_request_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Request) String() string { return protoimpl.X.MessageStringOf(x) } func (*Request) ProtoMessage() {} func (x *Request) ProtoReflect() protoreflect.Message { mi := &file_entity_request_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Request.ProtoReflect.Descriptor instead. func (*Request) Descriptor() ([]byte, []int) { return file_entity_request_proto_rawDescGZIP(), []int{0} } func (x *Request) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *Request) GetData() []byte { if x != nil { return x.Data } return nil } var File_entity_request_proto protoreflect.FileDescriptor var file_entity_request_proto_rawDesc = []byte{ 0x0a, 0x14, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x38, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_request_proto_rawDescOnce sync.Once file_entity_request_proto_rawDescData = file_entity_request_proto_rawDesc ) func file_entity_request_proto_rawDescGZIP() []byte { file_entity_request_proto_rawDescOnce.Do(func() { file_entity_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_request_proto_rawDescData) }) return file_entity_request_proto_rawDescData } var file_entity_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_request_proto_goTypes = []any{ (*Request)(nil), // 0: grpc.Request } var file_entity_request_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_request_proto_init() } func file_entity_request_proto_init() { if File_entity_request_proto != nil { return } if !protoimpl.UnsafeEnabled { file_entity_request_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Request); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_request_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_request_proto_goTypes, DependencyIndexes: file_entity_request_proto_depIdxs, MessageInfos: file_entity_request_proto_msgTypes, }.Build() File_entity_request_proto = out.File file_entity_request_proto_rawDesc = nil file_entity_request_proto_goTypes = nil file_entity_request_proto_depIdxs = nil } ================================================ FILE: grpc/response.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/response.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Code ResponseCode `protobuf:"varint,1,opt,name=code,proto3,enum=ResponseCode" json:"code,omitempty"` Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"` } func (x *Response) Reset() { *x = Response{} if protoimpl.UnsafeEnabled { mi := &file_entity_response_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Response) String() string { return protoimpl.X.MessageStringOf(x) } func (*Response) ProtoMessage() {} func (x *Response) ProtoReflect() protoreflect.Message { mi := &file_entity_response_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Response.ProtoReflect.Descriptor instead. func (*Response) Descriptor() ([]byte, []int) { return file_entity_response_proto_rawDescGZIP(), []int{0} } func (x *Response) GetCode() ResponseCode { if x != nil { return x.Code } return ResponseCode_OK } func (x *Response) GetMessage() string { if x != nil { return x.Message } return "" } func (x *Response) GetData() []byte { if x != nil { return x.Data } return nil } func (x *Response) GetError() string { if x != nil { return x.Error } return "" } func (x *Response) GetTotal() int64 { if x != nil { return x.Total } return 0 } var File_entity_response_proto protoreflect.FileDescriptor var file_entity_response_proto_rawDesc = []byte{ 0x0a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x1a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_response_proto_rawDescOnce sync.Once file_entity_response_proto_rawDescData = file_entity_response_proto_rawDesc ) func file_entity_response_proto_rawDescGZIP() []byte { file_entity_response_proto_rawDescOnce.Do(func() { file_entity_response_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_response_proto_rawDescData) }) return file_entity_response_proto_rawDescData } var file_entity_response_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_response_proto_goTypes = []any{ (*Response)(nil), // 0: grpc.Response (ResponseCode)(0), // 1: ResponseCode } var file_entity_response_proto_depIdxs = []int32{ 1, // 0: grpc.Response.code:type_name -> ResponseCode 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_entity_response_proto_init() } func file_entity_response_proto_init() { if File_entity_response_proto != nil { return } file_entity_response_code_proto_init() if !protoimpl.UnsafeEnabled { file_entity_response_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Response); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_response_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_response_proto_goTypes, DependencyIndexes: file_entity_response_proto_depIdxs, MessageInfos: file_entity_response_proto_msgTypes, }.Build() File_entity_response_proto = out.File file_entity_response_proto_rawDesc = nil file_entity_response_proto_goTypes = nil file_entity_response_proto_depIdxs = nil } ================================================ FILE: grpc/response_code.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/response_code.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type ResponseCode int32 const ( ResponseCode_OK ResponseCode = 0 ResponseCode_ERROR ResponseCode = 1 ) // Enum value maps for ResponseCode. var ( ResponseCode_name = map[int32]string{ 0: "OK", 1: "ERROR", } ResponseCode_value = map[string]int32{ "OK": 0, "ERROR": 1, } ) func (x ResponseCode) Enum() *ResponseCode { p := new(ResponseCode) *p = x return p } func (x ResponseCode) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (ResponseCode) Descriptor() protoreflect.EnumDescriptor { return file_entity_response_code_proto_enumTypes[0].Descriptor() } func (ResponseCode) Type() protoreflect.EnumType { return &file_entity_response_code_proto_enumTypes[0] } func (x ResponseCode) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use ResponseCode.Descriptor instead. func (ResponseCode) EnumDescriptor() ([]byte, []int) { return file_entity_response_code_proto_rawDescGZIP(), []int{0} } var File_entity_response_code_proto protoreflect.FileDescriptor var file_entity_response_code_proto_rawDesc = []byte{ 0x0a, 0x1a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x21, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_response_code_proto_rawDescOnce sync.Once file_entity_response_code_proto_rawDescData = file_entity_response_code_proto_rawDesc ) func file_entity_response_code_proto_rawDescGZIP() []byte { file_entity_response_code_proto_rawDescOnce.Do(func() { file_entity_response_code_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_response_code_proto_rawDescData) }) return file_entity_response_code_proto_rawDescData } var file_entity_response_code_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_entity_response_code_proto_goTypes = []any{ (ResponseCode)(0), // 0: ResponseCode } var file_entity_response_code_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_response_code_proto_init() } func file_entity_response_code_proto_init() { if File_entity_response_code_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_response_code_proto_rawDesc, NumEnums: 1, NumMessages: 0, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_response_code_proto_goTypes, DependencyIndexes: file_entity_response_code_proto_depIdxs, EnumInfos: file_entity_response_code_proto_enumTypes, }.Build() File_entity_response_code_proto = out.File file_entity_response_code_proto_rawDesc = nil file_entity_response_code_proto_goTypes = nil file_entity_response_code_proto_depIdxs = nil } ================================================ FILE: grpc/stream_message.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/stream_message.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type StreamMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Code StreamMessageCode `protobuf:"varint,1,opt,name=code,proto3,enum=grpc.StreamMessageCode" json:"code,omitempty"` NodeKey string `protobuf:"bytes,2,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` Error string `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"` } func (x *StreamMessage) Reset() { *x = StreamMessage{} if protoimpl.UnsafeEnabled { mi := &file_entity_stream_message_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *StreamMessage) String() string { return protoimpl.X.MessageStringOf(x) } func (*StreamMessage) ProtoMessage() {} func (x *StreamMessage) ProtoReflect() protoreflect.Message { mi := &file_entity_stream_message_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use StreamMessage.ProtoReflect.Descriptor instead. func (*StreamMessage) Descriptor() ([]byte, []int) { return file_entity_stream_message_proto_rawDescGZIP(), []int{0} } func (x *StreamMessage) GetCode() StreamMessageCode { if x != nil { return x.Code } return StreamMessageCode_PING } func (x *StreamMessage) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *StreamMessage) GetKey() string { if x != nil { return x.Key } return "" } func (x *StreamMessage) GetFrom() string { if x != nil { return x.From } return "" } func (x *StreamMessage) GetTo() string { if x != nil { return x.To } return "" } func (x *StreamMessage) GetData() []byte { if x != nil { return x.Data } return nil } func (x *StreamMessage) GetError() string { if x != nil { return x.Error } return "" } var File_entity_stream_message_proto protoreflect.FileDescriptor var file_entity_stream_message_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb7, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_stream_message_proto_rawDescOnce sync.Once file_entity_stream_message_proto_rawDescData = file_entity_stream_message_proto_rawDesc ) func file_entity_stream_message_proto_rawDescGZIP() []byte { file_entity_stream_message_proto_rawDescOnce.Do(func() { file_entity_stream_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_stream_message_proto_rawDescData) }) return file_entity_stream_message_proto_rawDescData } var file_entity_stream_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_stream_message_proto_goTypes = []any{ (*StreamMessage)(nil), // 0: grpc.StreamMessage (StreamMessageCode)(0), // 1: grpc.StreamMessageCode } var file_entity_stream_message_proto_depIdxs = []int32{ 1, // 0: grpc.StreamMessage.code:type_name -> grpc.StreamMessageCode 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_entity_stream_message_proto_init() } func file_entity_stream_message_proto_init() { if File_entity_stream_message_proto != nil { return } file_entity_stream_message_code_proto_init() if !protoimpl.UnsafeEnabled { file_entity_stream_message_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*StreamMessage); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_stream_message_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_stream_message_proto_goTypes, DependencyIndexes: file_entity_stream_message_proto_depIdxs, MessageInfos: file_entity_stream_message_proto_msgTypes, }.Build() File_entity_stream_message_proto = out.File file_entity_stream_message_proto_rawDesc = nil file_entity_stream_message_proto_goTypes = nil file_entity_stream_message_proto_depIdxs = nil } ================================================ FILE: grpc/stream_message_code.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/stream_message_code.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type StreamMessageCode int32 const ( // ping worker nodes to check their health StreamMessageCode_PING StreamMessageCode = 0 // ask worker node(s) to run task with given id StreamMessageCode_RUN_TASK StreamMessageCode = 1 // ask worker node(s) to cancel task with given id StreamMessageCode_CANCEL_TASK StreamMessageCode = 2 // insert data StreamMessageCode_INSERT_DATA StreamMessageCode = 3 // insert logs StreamMessageCode_INSERT_LOGS StreamMessageCode = 4 // send event StreamMessageCode_SEND_EVENT StreamMessageCode = 5 // install plugin StreamMessageCode_INSTALL_PLUGIN StreamMessageCode = 6 // uninstall plugin StreamMessageCode_UNINSTALL_PLUGIN StreamMessageCode = 7 // start plugin StreamMessageCode_START_PLUGIN StreamMessageCode = 8 // stop plugin StreamMessageCode_STOP_PLUGIN StreamMessageCode = 9 // connect StreamMessageCode_CONNECT StreamMessageCode = 10 // disconnect StreamMessageCode_DISCONNECT StreamMessageCode = 11 // send StreamMessageCode_SEND StreamMessageCode = 12 ) // Enum value maps for StreamMessageCode. var ( StreamMessageCode_name = map[int32]string{ 0: "PING", 1: "RUN_TASK", 2: "CANCEL_TASK", 3: "INSERT_DATA", 4: "INSERT_LOGS", 5: "SEND_EVENT", 6: "INSTALL_PLUGIN", 7: "UNINSTALL_PLUGIN", 8: "START_PLUGIN", 9: "STOP_PLUGIN", 10: "CONNECT", 11: "DISCONNECT", 12: "SEND", } StreamMessageCode_value = map[string]int32{ "PING": 0, "RUN_TASK": 1, "CANCEL_TASK": 2, "INSERT_DATA": 3, "INSERT_LOGS": 4, "SEND_EVENT": 5, "INSTALL_PLUGIN": 6, "UNINSTALL_PLUGIN": 7, "START_PLUGIN": 8, "STOP_PLUGIN": 9, "CONNECT": 10, "DISCONNECT": 11, "SEND": 12, } ) func (x StreamMessageCode) Enum() *StreamMessageCode { p := new(StreamMessageCode) *p = x return p } func (x StreamMessageCode) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (StreamMessageCode) Descriptor() protoreflect.EnumDescriptor { return file_entity_stream_message_code_proto_enumTypes[0].Descriptor() } func (StreamMessageCode) Type() protoreflect.EnumType { return &file_entity_stream_message_code_proto_enumTypes[0] } func (x StreamMessageCode) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use StreamMessageCode.Descriptor instead. func (StreamMessageCode) EnumDescriptor() ([]byte, []int) { return file_entity_stream_message_code_proto_rawDescGZIP(), []int{0} } var File_entity_stream_message_code_proto protoreflect.FileDescriptor var file_entity_stream_message_code_proto_rawDesc = []byte{ 0x0a, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x2a, 0xe2, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x55, 0x4e, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54, 0x5f, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x06, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x4e, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x0b, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x45, 0x4e, 0x44, 0x10, 0x0c, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_stream_message_code_proto_rawDescOnce sync.Once file_entity_stream_message_code_proto_rawDescData = file_entity_stream_message_code_proto_rawDesc ) func file_entity_stream_message_code_proto_rawDescGZIP() []byte { file_entity_stream_message_code_proto_rawDescOnce.Do(func() { file_entity_stream_message_code_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_stream_message_code_proto_rawDescData) }) return file_entity_stream_message_code_proto_rawDescData } var file_entity_stream_message_code_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_entity_stream_message_code_proto_goTypes = []any{ (StreamMessageCode)(0), // 0: grpc.StreamMessageCode } var file_entity_stream_message_code_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_stream_message_code_proto_init() } func file_entity_stream_message_code_proto_init() { if File_entity_stream_message_code_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_stream_message_code_proto_rawDesc, NumEnums: 1, NumMessages: 0, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_stream_message_code_proto_goTypes, DependencyIndexes: file_entity_stream_message_code_proto_depIdxs, EnumInfos: file_entity_stream_message_code_proto_enumTypes, }.Build() File_entity_stream_message_code_proto = out.File file_entity_stream_message_code_proto_rawDesc = nil file_entity_stream_message_code_proto_goTypes = nil file_entity_stream_message_code_proto_depIdxs = nil } ================================================ FILE: grpc/stream_message_data_task.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: entity/stream_message_data_task.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type StreamMessageDataTask struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` Data string `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } func (x *StreamMessageDataTask) Reset() { *x = StreamMessageDataTask{} if protoimpl.UnsafeEnabled { mi := &file_entity_stream_message_data_task_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *StreamMessageDataTask) String() string { return protoimpl.X.MessageStringOf(x) } func (*StreamMessageDataTask) ProtoMessage() {} func (x *StreamMessageDataTask) ProtoReflect() protoreflect.Message { mi := &file_entity_stream_message_data_task_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use StreamMessageDataTask.ProtoReflect.Descriptor instead. func (*StreamMessageDataTask) Descriptor() ([]byte, []int) { return file_entity_stream_message_data_task_proto_rawDescGZIP(), []int{0} } func (x *StreamMessageDataTask) GetTaskId() string { if x != nil { return x.TaskId } return "" } func (x *StreamMessageDataTask) GetData() string { if x != nil { return x.Data } return "" } var File_entity_stream_message_data_task_proto protoreflect.FileDescriptor var file_entity_stream_message_data_task_proto_rawDesc = []byte{ 0x0a, 0x25, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x44, 0x0a, 0x15, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_entity_stream_message_data_task_proto_rawDescOnce sync.Once file_entity_stream_message_data_task_proto_rawDescData = file_entity_stream_message_data_task_proto_rawDesc ) func file_entity_stream_message_data_task_proto_rawDescGZIP() []byte { file_entity_stream_message_data_task_proto_rawDescOnce.Do(func() { file_entity_stream_message_data_task_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_stream_message_data_task_proto_rawDescData) }) return file_entity_stream_message_data_task_proto_rawDescData } var file_entity_stream_message_data_task_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_entity_stream_message_data_task_proto_goTypes = []any{ (*StreamMessageDataTask)(nil), // 0: grpc.StreamMessageDataTask } var file_entity_stream_message_data_task_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_entity_stream_message_data_task_proto_init() } func file_entity_stream_message_data_task_proto_init() { if File_entity_stream_message_data_task_proto != nil { return } if !protoimpl.UnsafeEnabled { file_entity_stream_message_data_task_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*StreamMessageDataTask); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_entity_stream_message_data_task_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_entity_stream_message_data_task_proto_goTypes, DependencyIndexes: file_entity_stream_message_data_task_proto_depIdxs, MessageInfos: file_entity_stream_message_data_task_proto_msgTypes, }.Build() File_entity_stream_message_data_task_proto = out.File file_entity_stream_message_data_task_proto_rawDesc = nil file_entity_stream_message_data_task_proto_goTypes = nil file_entity_stream_message_data_task_proto_depIdxs = nil } ================================================ FILE: grpc/task.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: models/task.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type Task struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields XId string `protobuf:"bytes,1,opt,name=_id,json=Id,proto3" json:"_id,omitempty"` SpiderId string `protobuf:"bytes,2,opt,name=spider_id,json=spiderId,proto3" json:"spider_id,omitempty"` Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` NodeId string `protobuf:"bytes,6,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` Cmd string `protobuf:"bytes,8,opt,name=cmd,proto3" json:"cmd,omitempty"` Param string `protobuf:"bytes,9,opt,name=param,proto3" json:"param,omitempty"` Error string `protobuf:"bytes,10,opt,name=error,proto3" json:"error,omitempty"` Pid int32 `protobuf:"varint,16,opt,name=pid,proto3" json:"pid,omitempty"` RunType string `protobuf:"bytes,17,opt,name=run_type,json=runType,proto3" json:"run_type,omitempty"` ScheduleId string `protobuf:"bytes,18,opt,name=schedule_id,json=scheduleId,proto3" json:"schedule_id,omitempty"` Type string `protobuf:"bytes,19,opt,name=type,proto3" json:"type,omitempty"` } func (x *Task) Reset() { *x = Task{} if protoimpl.UnsafeEnabled { mi := &file_models_task_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Task) String() string { return protoimpl.X.MessageStringOf(x) } func (*Task) ProtoMessage() {} func (x *Task) ProtoReflect() protoreflect.Message { mi := &file_models_task_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Task.ProtoReflect.Descriptor instead. func (*Task) Descriptor() ([]byte, []int) { return file_models_task_proto_rawDescGZIP(), []int{0} } func (x *Task) GetXId() string { if x != nil { return x.XId } return "" } func (x *Task) GetSpiderId() string { if x != nil { return x.SpiderId } return "" } func (x *Task) GetStatus() string { if x != nil { return x.Status } return "" } func (x *Task) GetNodeId() string { if x != nil { return x.NodeId } return "" } func (x *Task) GetCmd() string { if x != nil { return x.Cmd } return "" } func (x *Task) GetParam() string { if x != nil { return x.Param } return "" } func (x *Task) GetError() string { if x != nil { return x.Error } return "" } func (x *Task) GetPid() int32 { if x != nil { return x.Pid } return 0 } func (x *Task) GetRunType() string { if x != nil { return x.RunType } return "" } func (x *Task) GetScheduleId() string { if x != nil { return x.ScheduleId } return "" } func (x *Task) GetType() string { if x != nil { return x.Type } return "" } var File_models_task_proto protoreflect.FileDescriptor var file_models_task_proto_rawDesc = []byte{ 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x22, 0x85, 0x02, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0f, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x6d, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x75, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_models_task_proto_rawDescOnce sync.Once file_models_task_proto_rawDescData = file_models_task_proto_rawDesc ) func file_models_task_proto_rawDescGZIP() []byte { file_models_task_proto_rawDescOnce.Do(func() { file_models_task_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_task_proto_rawDescData) }) return file_models_task_proto_rawDescData } var file_models_task_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_models_task_proto_goTypes = []any{ (*Task)(nil), // 0: grpc.Task } var file_models_task_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_models_task_proto_init() } func file_models_task_proto_init() { if File_models_task_proto != nil { return } if !protoimpl.UnsafeEnabled { file_models_task_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Task); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_models_task_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_models_task_proto_goTypes, DependencyIndexes: file_models_task_proto_depIdxs, MessageInfos: file_models_task_proto_msgTypes, }.Build() File_models_task_proto = out.File file_models_task_proto_rawDesc = nil file_models_task_proto_goTypes = nil file_models_task_proto_depIdxs = nil } ================================================ FILE: grpc/task_service.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.27.2 // source: services/task_service.proto package grpc import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type TaskServiceSendNotificationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields NodeKey string `protobuf:"bytes,1,opt,name=node_key,json=nodeKey,proto3" json:"node_key,omitempty"` TaskId string `protobuf:"bytes,2,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` } func (x *TaskServiceSendNotificationRequest) Reset() { *x = TaskServiceSendNotificationRequest{} if protoimpl.UnsafeEnabled { mi := &file_services_task_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *TaskServiceSendNotificationRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*TaskServiceSendNotificationRequest) ProtoMessage() {} func (x *TaskServiceSendNotificationRequest) ProtoReflect() protoreflect.Message { mi := &file_services_task_service_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use TaskServiceSendNotificationRequest.ProtoReflect.Descriptor instead. func (*TaskServiceSendNotificationRequest) Descriptor() ([]byte, []int) { return file_services_task_service_proto_rawDescGZIP(), []int{0} } func (x *TaskServiceSendNotificationRequest) GetNodeKey() string { if x != nil { return x.NodeKey } return "" } func (x *TaskServiceSendNotificationRequest) GetTaskId() string { if x != nil { return x.TaskId } return "" } var File_services_task_service_proto protoreflect.FileDescriptor var file_services_task_service_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x14, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x58, 0x0a, 0x22, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x32, 0xbd, 0x01, 0x0a, 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x28, 0x0a, 0x05, 0x46, 0x65, 0x74, 0x63, 0x68, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x3b, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_services_task_service_proto_rawDescOnce sync.Once file_services_task_service_proto_rawDescData = file_services_task_service_proto_rawDesc ) func file_services_task_service_proto_rawDescGZIP() []byte { file_services_task_service_proto_rawDescOnce.Do(func() { file_services_task_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_services_task_service_proto_rawDescData) }) return file_services_task_service_proto_rawDescData } var file_services_task_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_services_task_service_proto_goTypes = []any{ (*TaskServiceSendNotificationRequest)(nil), // 0: grpc.TaskServiceSendNotificationRequest (*StreamMessage)(nil), // 1: grpc.StreamMessage (*Request)(nil), // 2: grpc.Request (*Response)(nil), // 3: grpc.Response } var file_services_task_service_proto_depIdxs = []int32{ 1, // 0: grpc.TaskService.Subscribe:input_type -> grpc.StreamMessage 2, // 1: grpc.TaskService.Fetch:input_type -> grpc.Request 0, // 2: grpc.TaskService.SendNotification:input_type -> grpc.TaskServiceSendNotificationRequest 3, // 3: grpc.TaskService.Subscribe:output_type -> grpc.Response 3, // 4: grpc.TaskService.Fetch:output_type -> grpc.Response 3, // 5: grpc.TaskService.SendNotification:output_type -> grpc.Response 3, // [3:6] is the sub-list for method output_type 0, // [0:3] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_services_task_service_proto_init() } func file_services_task_service_proto_init() { if File_services_task_service_proto != nil { return } file_entity_request_proto_init() file_entity_response_proto_init() file_entity_stream_message_proto_init() if !protoimpl.UnsafeEnabled { file_services_task_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*TaskServiceSendNotificationRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_services_task_service_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 1, }, GoTypes: file_services_task_service_proto_goTypes, DependencyIndexes: file_services_task_service_proto_depIdxs, MessageInfos: file_services_task_service_proto_msgTypes, }.Build() File_services_task_service_proto = out.File file_services_task_service_proto_rawDesc = nil file_services_task_service_proto_goTypes = nil file_services_task_service_proto_depIdxs = nil } ================================================ FILE: grpc/task_service_grpc.pb.go ================================================ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 // - protoc v5.27.2 // source: services/task_service.proto package grpc import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.62.0 or later. const _ = grpc.SupportPackageIsVersion8 const ( TaskService_Subscribe_FullMethodName = "/grpc.TaskService/Subscribe" TaskService_Fetch_FullMethodName = "/grpc.TaskService/Fetch" TaskService_SendNotification_FullMethodName = "/grpc.TaskService/SendNotification" ) // TaskServiceClient is the client API for TaskService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type TaskServiceClient interface { Subscribe(ctx context.Context, opts ...grpc.CallOption) (TaskService_SubscribeClient, error) Fetch(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) SendNotification(ctx context.Context, in *TaskServiceSendNotificationRequest, opts ...grpc.CallOption) (*Response, error) } type taskServiceClient struct { cc grpc.ClientConnInterface } func NewTaskServiceClient(cc grpc.ClientConnInterface) TaskServiceClient { return &taskServiceClient{cc} } func (c *taskServiceClient) Subscribe(ctx context.Context, opts ...grpc.CallOption) (TaskService_SubscribeClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &TaskService_ServiceDesc.Streams[0], TaskService_Subscribe_FullMethodName, cOpts...) if err != nil { return nil, err } x := &taskServiceSubscribeClient{ClientStream: stream} return x, nil } type TaskService_SubscribeClient interface { Send(*StreamMessage) error CloseAndRecv() (*Response, error) grpc.ClientStream } type taskServiceSubscribeClient struct { grpc.ClientStream } func (x *taskServiceSubscribeClient) Send(m *StreamMessage) error { return x.ClientStream.SendMsg(m) } func (x *taskServiceSubscribeClient) CloseAndRecv() (*Response, error) { if err := x.ClientStream.CloseSend(); err != nil { return nil, err } m := new(Response) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *taskServiceClient) Fetch(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, TaskService_Fetch_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *taskServiceClient) SendNotification(ctx context.Context, in *TaskServiceSendNotificationRequest, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) err := c.cc.Invoke(ctx, TaskService_SendNotification_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // TaskServiceServer is the server API for TaskService service. // All implementations must embed UnimplementedTaskServiceServer // for forward compatibility type TaskServiceServer interface { Subscribe(TaskService_SubscribeServer) error Fetch(context.Context, *Request) (*Response, error) SendNotification(context.Context, *TaskServiceSendNotificationRequest) (*Response, error) mustEmbedUnimplementedTaskServiceServer() } // UnimplementedTaskServiceServer must be embedded to have forward compatible implementations. type UnimplementedTaskServiceServer struct { } func (UnimplementedTaskServiceServer) Subscribe(TaskService_SubscribeServer) error { return status.Errorf(codes.Unimplemented, "method Subscribe not implemented") } func (UnimplementedTaskServiceServer) Fetch(context.Context, *Request) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method Fetch not implemented") } func (UnimplementedTaskServiceServer) SendNotification(context.Context, *TaskServiceSendNotificationRequest) (*Response, error) { return nil, status.Errorf(codes.Unimplemented, "method SendNotification not implemented") } func (UnimplementedTaskServiceServer) mustEmbedUnimplementedTaskServiceServer() {} // UnsafeTaskServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to TaskServiceServer will // result in compilation errors. type UnsafeTaskServiceServer interface { mustEmbedUnimplementedTaskServiceServer() } func RegisterTaskServiceServer(s grpc.ServiceRegistrar, srv TaskServiceServer) { s.RegisterService(&TaskService_ServiceDesc, srv) } func _TaskService_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(TaskServiceServer).Subscribe(&taskServiceSubscribeServer{ServerStream: stream}) } type TaskService_SubscribeServer interface { SendAndClose(*Response) error Recv() (*StreamMessage, error) grpc.ServerStream } type taskServiceSubscribeServer struct { grpc.ServerStream } func (x *taskServiceSubscribeServer) SendAndClose(m *Response) error { return x.ServerStream.SendMsg(m) } func (x *taskServiceSubscribeServer) Recv() (*StreamMessage, error) { m := new(StreamMessage) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func _TaskService_Fetch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(TaskServiceServer).Fetch(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: TaskService_Fetch_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TaskServiceServer).Fetch(ctx, req.(*Request)) } return interceptor(ctx, in, info, handler) } func _TaskService_SendNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(TaskServiceSendNotificationRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(TaskServiceServer).SendNotification(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: TaskService_SendNotification_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TaskServiceServer).SendNotification(ctx, req.(*TaskServiceSendNotificationRequest)) } return interceptor(ctx, in, info, handler) } // TaskService_ServiceDesc is the grpc.ServiceDesc for TaskService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var TaskService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "grpc.TaskService", HandlerType: (*TaskServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Fetch", Handler: _TaskService_Fetch_Handler, }, { MethodName: "SendNotification", Handler: _TaskService_SendNotification_Handler, }, }, Streams: []grpc.StreamDesc{ { StreamName: "Subscribe", Handler: _TaskService_Subscribe_Handler, ClientStreams: true, }, }, Metadata: "services/task_service.proto", } ================================================ FILE: k8s/crawlab-master.yaml ================================================ apiVersion: v1 kind: Service metadata: name: crawlab namespace: crawlab spec: ports: - port: 80 targetPort: 8080 name: http - name: grpc port: 9666 targetPort: 9666 selector: app: crawlab-master type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: crawlab-master namespace: crawlab spec: selector: matchLabels: app: crawlab-master template: metadata: labels: app: crawlab-master spec: containers: - image: crawlabteam/crawlab:latest imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_NODE_MASTER value: "Y" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SETTING_ALLOWREGISTER value: "Y" - name: CRAWLAB_SERVER_LANG_NODE value: "N" - name: CRAWLAB_SERVER_LANG_JAVA value: "N" - name: CRAWLAB_SERVER_LANG_DOTNET value: "N" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" ports: - containerPort: 8080 name: crawlab - containerPort: 9666 name: grpc ================================================ FILE: k8s/crawlab-worker.yaml ================================================ apiVersion: apps/v1 kind: Deployment metadata: name: crawlab-worker namespace: crawlab spec: replicas: 2 selector: matchLabels: app: crawlab-worker template: metadata: labels: app: crawlab-worker spec: containers: - image: crawlabteam/crawlab:latest imagePullPolicy: Always name: crawlab env: - name: CRAWLAB_NODE_MASTER value: "N" - name: CRAWLAB_MONGO_HOST value: "mongo" - name: CRAWLAB_REDIS_ADDRESS value: "redis" - name: CRAWLAB_SERVER_LANG_NODE value: "Y" - name: CRAWLAB_SERVER_LANG_JAVA value: "Y" - name: CRAWLAB_SERVER_LANG_DOTNET value: "Y" - name: CRAWLAB_SERVER_REGISTER_TYPE value: "hostname" - name: CRAWLAB_GRPC_ADDRESS value: "crawlab" - name: CRAWLAB_FS_FILER_URL value: "http://crawlab/api/filer" ================================================ FILE: k8s/mongo-pv.yaml ================================================ apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv-volume namespace: crawlab labels: type: local spec: storageClassName: manual capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: path: "/data/k8s/mongodb/data" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pv-claim namespace: crawlab spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 10Gi ================================================ FILE: k8s/mongo.yaml ================================================ apiVersion: v1 kind: Service metadata: name: mongo namespace: crawlab spec: ports: - port: 27017 selector: app: mongo clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: mongo namespace: crawlab spec: selector: matchLabels: app: mongo strategy: type: Recreate template: metadata: labels: app: mongo spec: containers: - image: mongo:4 name: mongo ports: - containerPort: 27017 name: mongo volumeMounts: - name: mongo-persistent-storage mountPath: /data/db volumes: - name: mongo-persistent-storage persistentVolumeClaim: claimName: mongo-pv-claim ================================================ FILE: k8s/ns.yaml ================================================ apiVersion: v1 kind: Namespace metadata: name: crawlab ================================================ FILE: k8s/redis.yaml ================================================ apiVersion: v1 kind: Service metadata: name: redis namespace: crawlab spec: ports: - port: 6379 selector: app: redis clusterIP: None --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: redis namespace: crawlab spec: selector: matchLabels: app: redis strategy: type: Recreate template: metadata: labels: app: redis spec: containers: - image: redis name: redis ports: - containerPort: 6379 name: redis ================================================ FILE: nginx/crawlab.conf ================================================ server { gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_comp_level 2; gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png image/x-icon; gzip_vary off; gzip_disable "MSIE [1-6]\."; client_max_body_size 200m; listen 8080; root /app/dist; index index.html; location /api/ { rewrite /api/(.*) /$1 break; proxy_pass http://localhost:8000/; } } ================================================ FILE: scripts/validate-backend.sh ================================================ #!/bin/sh IFS=$'\n' pattern=^replace content=$(cat ./backend/go.mod) for line in $content do if [[ $line =~ $pattern ]]; then echo "Invalid ./backend/go.mod, which should not contain \"^replace\"" exit 1 fi done ================================================ FILE: template-parser/.gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ .idea .DS_Store ================================================ FILE: template-parser/LICENSE ================================================ MIT License Copyright (c) 2021 Crawlab Team 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. ================================================ FILE: template-parser/README.md ================================================ # template-parser ================================================ FILE: template-parser/entity.go ================================================ package parser // type: model / attribute // {{task.spider.name}} // => ================================================ FILE: template-parser/func.go ================================================ package parser func Parse(template string, args ...interface{}) (content string, err error) { return ParseGeneral(template, args...) } func ParseGeneral(template string, args ...interface{}) (content string, err error) { p, _ := NewGeneralParser() if err := p.Parse(template); err != nil { return "", err } return p.Render(args...) } ================================================ FILE: template-parser/general_parser.go ================================================ package parser import ( "encoding/json" "errors" "fmt" "github.com/robertkrimen/otto" "regexp" "strings" ) type GeneralParser struct { tagPattern string tagRegexp *regexp.Regexp mathPattern string mathRegexp *regexp.Regexp template string indexes [][]int matches [][]string placeholders []string variables []Variable vm *otto.Otto } const VariableNameResult = "result" const ValueNameNA = "N/A" func (p *GeneralParser) Parse(template string) (err error) { p.template = template p.indexes = p.tagRegexp.FindAllStringIndex(template, -1) p.matches = p.tagRegexp.FindAllStringSubmatch(template, -1) for _, arr := range p.matches { p.placeholders = append(p.placeholders, arr[1]) } return nil } func (p *GeneralParser) Render(args ...interface{}) (content string, err error) { // render tag content content, err = p.renderTagContent(args...) if err != nil { return content, err } // render math content content, err = p.renderMathContent(content) if err != nil { return content, err } return content, nil } func (p *GeneralParser) renderTagContent(args ...interface{}) (content string, err error) { // validate if len(args) == 0 { return "", errors.New("no arguments") } // first argument arg := args[0] // content content = p.template // old strings var oldStrList []string for _, index := range p.indexes { // old string oldStr := content[index[0]:index[1]] oldStrList = append(oldStrList, oldStr) } // iterate placeholders for i, placeholder := range p.placeholders { // variable v, err := NewVariable(arg, placeholder) if err != nil { return "", err } // value value, err := v.GetValue() if err != nil || value == nil { value = ValueNameNA } // old string oldStr := oldStrList[i] // new string var newStr string switch value.(type) { case string: newStr = value.(string) default: newStrBytes, err := json.Marshal(value) if err != nil { return "", err } newStr = string(newStrBytes) } // replace old string with new string content = strings.Replace(content, oldStr, newStr, 1) } return content, nil } func (p *GeneralParser) renderMathContent(inputContent string) (content string, err error) { content = inputContent indexes := p.mathRegexp.FindAllStringIndex(inputContent, -1) matches := p.mathRegexp.FindAllStringSubmatch(inputContent, -1) // old strings var oldStrList []string for _, index := range indexes { // old string oldStr := content[index[0]:index[1]] oldStrList = append(oldStrList, oldStr) } // iterate matches for i, m := range matches { // js script to run to get evaluate result script := fmt.Sprintf("%s = %s; %s", VariableNameResult, m[1], VariableNameResult) // replace NA script = strings.ReplaceAll(script, ValueNameNA, "NaN") // value value, err := p.vm.Run(script) if err != nil { return "", err } // old string oldStr := oldStrList[i] // new string newStr := value.String() // replace old string with new string content = strings.Replace(content, oldStr, newStr, 1) } return content, nil } func (p *GeneralParser) GetPlaceholders() (placeholders []string) { return p.placeholders } func NewGeneralParser() (p Parser, err error) { // tag regexp tagPrefix := "\\{\\{" tagSuffix := "\\}\\}" tagBasicChars := "\\$\\.\\w_" tagAssociateChars := "\\[\\]:" tagPattern := fmt.Sprintf( "%s *([%s%s]+) *%s", tagPrefix, tagBasicChars, tagAssociateChars, tagSuffix, ) tagRegexp, err := regexp.Compile(tagPattern) if err != nil { return nil, err } // math regexp mathPrefix := "\\{#" mathSuffix := "#\\}" mathBasicChars := " \\(\\)" mathOpChars := "\\+\\-\\*/%" mathNumChars := "\\d\\." mathSpecialChars := "(?:NaN|null)" mathPattern := fmt.Sprintf( "%s *([%s%s%s%s]+) *%s", mathPrefix, mathBasicChars, mathOpChars, mathNumChars, mathSpecialChars, mathSuffix, ) mathRegexp, err := regexp.Compile(mathPattern) if err != nil { return nil, err } // math vm vm := otto.New() // parser p = &GeneralParser{ tagPattern: tagPattern, tagRegexp: tagRegexp, mathPattern: mathPattern, mathRegexp: mathRegexp, vm: vm, } return p, nil } ================================================ FILE: template-parser/go.mod ================================================ module github.com/crawlab-team/crawlab/template-parser go 1.22 replace github.com/crawlab-team/crawlab/db => ../db require ( github.com/crawlab-team/crawlab/db v0.0.0-20240614095218-7b4ee8399ab0 github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.1 ) require ( github.com/apex/log v1.9.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: template-parser/go.sum ================================================ 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 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/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= 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/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 h1:ewTtJ72GFy2e0e8uyiDwMG3pKCS5mBh+hdSTYsPKEP8= github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 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.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 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/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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.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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= ================================================ FILE: template-parser/interfaces.go ================================================ package parser type Entity interface { GetType() string SetType(string) GetName() string SetName(string) } ================================================ FILE: template-parser/parser.go ================================================ package parser type Parser interface { Parse(template string) (err error) Render(args ...interface{}) (content string, err error) } ================================================ FILE: template-parser/test/general_parser_test.go ================================================ package test import ( "fmt" "github.com/crawlab-team/crawlab/db/mongo" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "testing" ) func TestGeneralParser(t *testing.T) { p, _ := parser.NewGeneralParser() content := `The task {{ $.node }} (enabled: {{$.node.enabled}}) has completed. Yours, {{$.user[create]}}` err := p.Parse(content) fmt.Println(p.(*parser.GeneralParser).GetPlaceholders()) require.Nil(t, err) } func TestGeneralParser_Parse(t *testing.T) { var err error t.Cleanup(cleanup) nodeId := primitive.NewObjectID() _, err = mongo.GetMongoCol("nodes").Insert(bson.M{ "_id": nodeId, "name": "Test Node", "enabled": true, "settings": bson.M{ "max_runners": 8, }, }) require.Nil(t, err) spiderId := primitive.NewObjectID() _, err = mongo.GetMongoCol("spiders").Insert(bson.M{ "_id": spiderId, }) require.Nil(t, err) _, err = mongo.GetMongoCol("spider_stats").Insert(bson.M{ "_id": spiderId, "result_count": 5000, }) require.Nil(t, err) userId := primitive.NewObjectID() _, err = mongo.GetMongoCol("users").Insert(bson.M{ "_id": userId, "no": 1001, "username": "Test Username", }) require.Nil(t, err) userIdUpdate := primitive.NewObjectID() _, err = mongo.GetMongoCol("users").Insert(bson.M{ "_id": userIdUpdate, "no": 1002, "username": "Test2 Username", }) require.Nil(t, err) taskId := primitive.NewObjectID() task := bson.M{ "_id": taskId, "node_id": nodeId, "spider_id": spiderId, } _, err = mongo.GetMongoCol("task_stats").Insert(bson.M{ "_id": taskId, "result_count": 100, }) require.Nil(t, err) _, err = mongo.GetMongoCol("artifacts").Insert(bson.M{ "_id": taskId, "_sys": bson.M{ "create_uid": userId, "update_uid": userIdUpdate, }, }) p, _ := parser.NewGeneralParser() template := `The task on node {{ $.node.name }} (enabled: {{$.node.enabled}}, max_runners: {{$.node.settings.max_runners}}) has completed. Task Result Count: {{ $.:task_stat.result_count }} Spider Result Count: {{ $.spider:stat.result_count }} Yours, {{$.user.username}} ({{$.user.no}}) and {{$.user[update].username}} ({{$.user[update].no}})` err = p.Parse(template) require.Nil(t, err) content, err := p.Render(task) require.Nil(t, err) require.Equal(t, `The task on node Test Node (enabled: true, max_runners: 8) has completed. Task Result Count: 100 Spider Result Count: 5000 Yours, Test Username (1001) and Test2 Username (1002)`, content) } func TestGeneralParser_ParseMath(t *testing.T) { var err error t.Cleanup(cleanup) taskId := primitive.NewObjectID() task := bson.M{ "_id": taskId, } _, err = mongo.GetMongoCol("task_stats").Insert(bson.M{ "_id": taskId, "wait_duration": 20000, "runtime_duration": 80000, "total_duration": 100000, "result_count": 500, }) require.Nil(t, err) p, _ := parser.NewGeneralParser() template := `The task has completed. Wait Duration: {# {{ $.:task_stat.wait_duration }} / 1000 #} Runtime Duration: {# {{$.:task_stat.runtime_duration}} / 1000 #} Total Duration: {# ({{$.:task_stat.wait_duration}} + {{$.:task_stat.runtime_duration}}) / 1000 #} Result Count: {{$.:task_stat.result_count}} Avg Results per Sec: {# {{$.:task_stat.result_count}} / ({{$.:task_stat.total_duration}} / 1000) #} ` err = p.Parse(template) require.Nil(t, err) content, err := p.Render(task) require.Nil(t, err) require.Equal(t, `The task has completed. Wait Duration: 20 Runtime Duration: 80 Total Duration: 100 Result Count: 500 Avg Results per Sec: 5 `, content) } func cleanup() { _ = mongo.GetMongoCol("nodes").Delete(nil) _ = mongo.GetMongoCol("spiders").Delete(nil) _ = mongo.GetMongoCol("spider_stats").Delete(nil) _ = mongo.GetMongoCol("tasks").Delete(nil) _ = mongo.GetMongoCol("task_stats").Delete(nil) _ = mongo.GetMongoCol("users").Delete(nil) } ================================================ FILE: template-parser/variable.go ================================================ package parser import ( "encoding/json" "errors" "fmt" "github.com/crawlab-team/crawlab/db/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "regexp" "strings" ) var userRegexp, _ = regexp.Compile("^user(?:\\[(\\w+)\\])?$") var extRegexp, _ = regexp.Compile("^(\\w+)?:(\\w+)") type Variable struct { root interface{} tokens []string doc bson.M } func (v *Variable) GetValue() (value interface{}, err error) { return v.getNodeByIndex(len(v.tokens) - 1) } func (v *Variable) getNodeByIndex(index int) (result interface{}, err error) { node := v.doc for i := 0; i < index && i < len(v.tokens); i++ { nextIndex := i + 1 if nextIndex < len(v.tokens)-1 { // root or intermediate node } else { // value return v.getNextValue(node, i), nil } // next node node, err = v.getNextNode(node, i) if err != nil { return nil, err } if node == nil { return nil, nil } } return node, nil } func (v *Variable) getNextNode(currentNode bson.M, currentIndex int) (nextNode bson.M, err error) { // next index and token nextIndex := currentIndex + 1 nextToken := v.tokens[nextIndex] // attempt to get attribute in current node nextNodeRes, ok := currentNode[nextToken] if ok { nextNode, ok = nextNodeRes.(bson.M) if ok { return nextNode, nil } } // if next token is user or user[] if userRegexp.MatchString(nextToken) { return v.getNextNodeUserAction(currentNode, nextIndex, nextToken) } // if next token is : if extRegexp.MatchString(nextToken) { return v.getNextNodeExt(currentNode, nextIndex, nextToken) } // model model := nextToken // next id nextId, err := v._getNodeModelId(currentNode, model, nextIndex) if err != nil { return nil, err } // mongo collection name colName := fmt.Sprintf("%ss", model) // get next node from mongo collection if err := mongo.GetMongoCol(colName).FindId(nextId).One(&nextNode); err != nil { return nil, err } return nextNode, nil } func (v *Variable) getNextNodeUserAction(currentNode bson.M, nextIndex int, nextToken string) (nextNode bson.M, err error) { // action matches := userRegexp.FindStringSubmatch(nextToken) action := "create" if len(matches) > 1 && matches[1] != "" { action = matches[1] } // id id, err := v._getCurrentNodeId(currentNode, nextIndex) if err != nil { return nil, err } // artifact var artifact bson.M if err := mongo.GetMongoCol("artifacts").FindId(id).One(&artifact); err != nil { return nil, err } // artifact._sys sysRes, ok := artifact["_sys"] if !ok { return nil, errors.New(fmt.Sprintf("_sys not exists in artifact of %s", strings.Join(v.tokens[:nextIndex], "."))) } sys, ok := sysRes.(bson.M) if !ok { return nil, errors.New(fmt.Sprintf("_sys is invalid in artifact of %s", strings.Join(v.tokens[:nextIndex], "."))) } // _uid uidRes, _ := sys[action+"_uid"] uid, _ := uidRes.(primitive.ObjectID) if err := mongo.GetMongoCol("users").FindId(uid).One(&nextNode); err != nil { return nil, err } return nextNode, nil } func (v *Variable) getNextNodeExt(currentNode bson.M, nextIndex int, nextToken string) (nextNode bson.M, err error) { matches := extRegexp.FindStringSubmatch(nextToken) var model, ext string var mode int if matches[1] == "" { // :_ mode = 0 arr := strings.Split(matches[2], "_") model = arr[0] ext = arr[1] } else { // : mode = 1 model = matches[1] ext = matches[2] } // id var id primitive.ObjectID switch mode { case 0: // id = currentNode._id id, err = v._getCurrentNodeId(currentNode, nextIndex) if err != nil { return nil, err } case 1: // id = currentNode._id id, err = v._getNodeModelId(currentNode, model, nextIndex) if err != nil { return nil, err } default: return nil, errors.New(fmt.Sprintf("invalid mode: %d", mode)) } // ext colName := fmt.Sprintf("%s_%ss", model, ext) if err := mongo.GetMongoCol(colName).FindId(id).One(&nextNode); err != nil { return nil, err } return nextNode, nil } func (v *Variable) getNextValue(currentNode bson.M, currentIndex int) (nextValue interface{}) { // next index and token nextIndex := currentIndex + 1 nextToken := v.tokens[nextIndex] // next value nextValue, _ = currentNode[nextToken] return nextValue } func (v *Variable) _getCurrentNodeId(currentNode bson.M, nextIndex int) (id primitive.ObjectID, err error) { idRes, ok := currentNode["_id"] if !ok { return id, errors.New(fmt.Sprintf("%s is not available in %s", "_id", strings.Join(v.tokens[:nextIndex], "."))) } switch idRes.(type) { case string: idStr, ok := idRes.(string) if !ok { return id, errors.New(fmt.Sprintf("%s is not ObjectId in %s", "_id", strings.Join(v.tokens[:nextIndex], "."))) } id, err = primitive.ObjectIDFromHex(idStr) if err != nil { return id, errors.New(fmt.Sprintf("%s is not ObjectId in %s", "_id", strings.Join(v.tokens[:nextIndex], "."))) } return id, nil case primitive.ObjectID: return idRes.(primitive.ObjectID), nil default: return id, errors.New(fmt.Sprintf("%s is not ObjectId in %s", "_id", strings.Join(v.tokens[:nextIndex], "."))) } } func (v *Variable) _getNodeModelId(currentNode bson.M, model string, nextIndex int) (id primitive.ObjectID, err error) { nextIdKey := fmt.Sprintf("%s_id", model) nextIdRes, ok := currentNode[nextIdKey] if !ok { return id, errors.New(fmt.Sprintf("%s is not available in %s", nextIdKey, strings.Join(v.tokens[:nextIndex], "."))) } nextId, ok := nextIdRes.(primitive.ObjectID) if !ok { nextIdStr, ok := nextIdRes.(string) if !ok { return id, errors.New(fmt.Sprintf("%s is not ObjectId in %s", nextIdKey, strings.Join(v.tokens[:nextIndex], "."))) } nextId, err = primitive.ObjectIDFromHex(nextIdStr) if err != nil { return id, err } } if nextId.IsZero() { return id, nil } return nextId, nil } func NewVariable(root interface{}, placeholder string) (v *Variable, err error) { // validate if placeholder == "" { return nil, errors.New("empty placeholder") } if !strings.HasPrefix(placeholder, "$") { return nil, errors.New("not start with $") } // tokens tokens := strings.Split(placeholder, ".") // document data, err := json.Marshal(root) if err != nil { return nil, err } var doc bson.M if err := json.Unmarshal(data, &doc); err != nil { return nil, err } v = &Variable{ root: root, tokens: tokens, doc: doc, } return v, nil } ================================================ FILE: trace/.gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ .idea .DS_Store ================================================ FILE: trace/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2021, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: trace/README.md ================================================ # go-trace Trace stack tools ================================================ FILE: trace/go.mod ================================================ module github.com/crawlab-team/crawlab/trace go 1.22 require github.com/ztrue/tracerr v0.4.0 ================================================ FILE: trace/go.sum ================================================ github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04= github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk= ================================================ FILE: trace/trace.go ================================================ package trace import "github.com/ztrue/tracerr" func PrintError(err error) { err = tracerr.Wrap(err) if err != nil { tracerr.Print(err) } } func TraceError(err error) error { err = tracerr.Wrap(err) if err != nil { tracerr.Print(err) } return err } func Error(err error) error { return tracerr.Wrap(err) } ================================================ FILE: vcs/.github/workflows/test.yml ================================================ name: Test on: [ push, pull_request ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Go environment uses: actions/setup-go@v2.1.3 with: go-version: 1.18 - name: Configure Git run: | git config --global user.name "Marvin Zhang" git config --global user.email "tikazyq@163.com" - name: Write Credentials run: | echo '${{ secrets.CREDENTIAL_JSON }}' > $GITHUB_WORKSPACE/credentials.json echo '${{ secrets.CREDENTIAL_JSON }}' > $GITHUB_WORKSPACE/test/credentials.json ls -l $GITHUB_WORKSPACE/test mkdir -p $GITHUB_WORKSPACE/.ssh echo "${{ secrets.SSH_KEY }}" > $GITHUB_WORKSPACE/id_rsa ls -la $GITHUB_WORKSPACE echo "GITHUB_WORKSPACE: $GITHUB_WORKSPACE" - name: Install run: go mod tidy - name: Run Tests run: go test ./... -race ================================================ FILE: vcs/.gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ .DS_Store .idea/ tmp/ test/credentials.json id_rsa* credentials.json coverage.txt ================================================ FILE: vcs/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2020, Crawlab Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. ================================================ FILE: vcs/README.md ================================================ # crawlab-vcs Version Control System (VCS) for Crawlab ================================================ FILE: vcs/constants.go ================================================ package vcs const ( GitRemoteNameOrigin = "origin" GitRemoteNameUpstream = "upstream" GitRemoteNameCrawlab = "crawlab" ) const GitDefaultRemoteName = GitRemoteNameOrigin const ( GitBranchNameMaster = "master" GitBranchNameMain = "main" GitBranchNameRelease = "release" GitBranchNameTest = "test" GitBranchNameDevelop = "develop" ) const GitDefaultBranchName = GitBranchNameMaster type GitAuthType int const ( GitAuthTypeNone GitAuthType = iota GitAuthTypeHTTP GitAuthTypeSSH ) type GitInitType int const ( GitInitTypeFs GitInitType = iota GitInitTypeMem ) const ( GitRefTypeBranch = "branch" GitRefTypeTag = "tag" ) ================================================ FILE: vcs/entity.go ================================================ package vcs import ( "time" ) type GitOptions struct { checkout []GitCheckoutOption } type GitRef struct { Type string `json:"type"` Name string `json:"name"` FullName string `json:"full_name"` Hash string `json:"hash"` Timestamp time.Time `json:"timestamp"` RemoteTrack string `json:"remote_track"` } type GitLog struct { Hash string `json:"hash"` Msg string `json:"msg"` AuthorName string `json:"author_name"` AuthorEmail string `json:"author_email"` Timestamp time.Time `json:"timestamp"` Refs []GitRef `json:"refs"` } type GitFileStatus struct { Path string `json:"path"` Name string `json:"name"` IsDir bool `json:"is_dir"` Staging string `json:"staging"` Worktree string `json:"worktree"` Extra string `json:"extra"` Children []GitFileStatus `json:"children"` } ================================================ FILE: vcs/errors.go ================================================ package vcs import "errors" var ( ErrInvalidArgsLength = errors.New("invalid arguments length") ErrUnsupportedType = errors.New("unsupported type") ErrInvalidAuthType = errors.New("invalid auth type") ErrInvalidOptions = errors.New("invalid options") ErrRepoAlreadyExists = errors.New("repo already exists") ErrInvalidRepoPath = errors.New("invalid repo path") ErrUnableToGetCurrentBranch = errors.New("unable to get current branch") ErrUnableToCloneWithEmptyRemoteUrl = errors.New("unable to clone with empty remote url") ErrInvalidHeadRef = errors.New("invalid head ref") ErrNoMatchedRemoteBranch = errors.New("no matched remote branch") ) ================================================ FILE: vcs/git.go ================================================ package vcs import ( "errors" "github.com/apex/log" "github.com/crawlab-team/crawlab/trace" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/http" gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" "golang.org/x/crypto/ssh" "io" "os" "path" "regexp" "sort" "strings" ) var headRefRegexp, _ = regexp.Compile("^ref: (.*)") type GitClient struct { // settings path string remoteUrl string isMem bool authType GitAuthType username string password string privateKey string privateKeyPath string defaultBranch string defaultInit bool // internals r *git.Repository } func (c *GitClient) Init() (err error) { initType := c.getInitType() switch initType { case GitInitTypeFs: err = c.initFs() case GitInitTypeMem: err = c.initMem() } if err != nil { return err } return nil } func (c *GitClient) Dispose() (err error) { switch c.getInitType() { case GitInitTypeFs: if err := os.RemoveAll(c.path); err != nil { return trace.TraceError(err) } case GitInitTypeMem: GitMemStorages.Delete(c.path) GitMemFileSystem.Delete(c.path) } return nil } func (c *GitClient) Clone() (err error) { // validate if c.remoteUrl == "" { return ErrUnableToCloneWithEmptyRemoteUrl } // auth auth, err := c.getGitAuth() if err != nil { return err } // options o := &git.CloneOptions{ URL: c.remoteUrl, Auth: auth, } // clone _, err = git.PlainClone(c.path, false, o) if err != nil { return err } return nil } func (c *GitClient) Checkout(opts ...GitCheckoutOption) (err error) { // worktree wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } // apply options o := &git.CheckoutOptions{} for _, opt := range opts { opt(o) } // checkout to the branch if err := wt.Checkout(o); err != nil { return trace.TraceError(err) } return nil } func (c *GitClient) Commit(msg string, opts ...GitCommitOption) (err error) { // worktree wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } // apply options o := &git.CommitOptions{} for _, opt := range opts { opt(o) } // commit if _, err := wt.Commit(msg, o); err != nil { return trace.TraceError(err) } return nil } func (c *GitClient) Pull(opts ...GitPullOption) (err error) { // worktree wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } // auth auth, err := c.getGitAuth() if err != nil { return err } if auth != nil { opts = append(opts, WithAuthPull(auth)) } // apply options o := &git.PullOptions{} for _, opt := range opts { opt(o) } // pull if err := wt.Pull(o); err != nil { if errors.Is(err, transport.ErrEmptyRemoteRepository) { return nil } if errors.Is(err, transport.ErrEmptyUploadPackRequest) { return nil } if errors.Is(err, git.NoErrAlreadyUpToDate) { return nil } if errors.Is(err, git.ErrNonFastForwardUpdate) { return nil } return trace.TraceError(err) } return nil } func (c *GitClient) Push(opts ...GitPushOption) (err error) { // auth auth, err := c.getGitAuth() if err != nil { return err } if auth != nil { opts = append(opts, WithAuthPush(auth)) } // apply options o := &git.PushOptions{} for _, opt := range opts { opt(o) } // push if err := c.r.Push(o); err != nil { return trace.TraceError(err) } return nil } func (c *GitClient) Reset(opts ...GitResetOption) (err error) { // apply options o := &git.ResetOptions{ Mode: git.HardReset, } for _, opt := range opts { opt(o) } // worktree wt, err := c.r.Worktree() if err != nil { return err } // reset if err := wt.Reset(o); err != nil { return err } // clean if err := wt.Clean(&git.CleanOptions{Dir: true}); err != nil { return err } return nil } func (c *GitClient) CreateBranch(branch, remote string, ref *plumbing.Reference) (err error) { return c.createBranch(branch, remote, ref) } func (c *GitClient) CheckoutBranchFromRef(branch string, ref *plumbing.Reference, opts ...GitCheckoutOption) (err error) { return c.CheckoutBranchWithRemote(branch, "", ref, opts...) } func (c *GitClient) CheckoutBranchWithRemoteFromRef(branch, remote string, ref *plumbing.Reference, opts ...GitCheckoutOption) (err error) { return c.CheckoutBranchWithRemote(branch, remote, ref, opts...) } func (c *GitClient) CheckoutBranch(branch string, opts ...GitCheckoutOption) (err error) { return c.CheckoutBranchWithRemote(branch, "", nil, opts...) } func (c *GitClient) CheckoutBranchWithRemote(branch, remote string, ref *plumbing.Reference, opts ...GitCheckoutOption) (err error) { if remote == "" { remote = GitRemoteNameOrigin } // remote if _, err := c.r.Remote(remote); err != nil { return trace.TraceError(err) } // check if the branch exists _, err = c.r.Branch(branch) if err != nil { if errors.Is(err, git.ErrBranchNotFound) { // create a new branch if it does not exist if err := c.createBranch(branch, remote, ref); err != nil { return err } _, err = c.r.Branch(branch) if err != nil { return trace.TraceError(err) } } else { return trace.TraceError(err) } } // add to options opts = append(opts, WithBranch(branch)) return c.Checkout(opts...) } func (c *GitClient) CheckoutHash(hash string, opts ...GitCheckoutOption) (err error) { // add to options opts = append(opts, WithHash(hash)) return c.Checkout(opts...) } func (c *GitClient) MoveBranch(from, to string) (err error) { wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } if err := wt.Checkout(&git.CheckoutOptions{ Create: true, Branch: plumbing.NewBranchReferenceName(to), }); err != nil { return trace.TraceError(err) } fromRef, err := c.r.Reference(plumbing.NewBranchReferenceName(from), false) if err != nil { return trace.TraceError(err) } if err := c.r.Storer.RemoveReference(fromRef.Name()); err != nil { return trace.TraceError(err) } return nil } func (c *GitClient) CommitAll(msg string, opts ...GitCommitOption) (err error) { // worktree wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } // add all files if _, err := wt.Add("."); err != nil { return trace.TraceError(err) } return c.Commit(msg, opts...) } func (c *GitClient) GetLogs() (logs []GitLog, err error) { iter, err := c.r.Log(&git.LogOptions{ All: true, }) if err != nil { return nil, trace.TraceError(err) } if err := iter.ForEach(func(commit *object.Commit) error { gitLog := GitLog{ Hash: commit.Hash.String(), Msg: commit.Message, AuthorName: commit.Author.Name, AuthorEmail: commit.Author.Email, Timestamp: commit.Author.When, } logs = append(logs, gitLog) return nil }); err != nil { return nil, trace.TraceError(err) } return } func (c *GitClient) GetLogsWithRefs() (logs []GitLog, err error) { // logs without tags logs, err = c.GetLogs() if err != nil { return nil, err } // branches branches, err := c.GetBranches() if err != nil { return nil, err } // tags tags, err := c.GetTags() if err != nil { return nil, err } // refs refs := append(branches, tags...) // refs map refsMap := map[string][]GitRef{} for _, ref := range refs { _, ok := refsMap[ref.Hash] if !ok { refsMap[ref.Hash] = []GitRef{} } refsMap[ref.Hash] = append(refsMap[ref.Hash], ref) } // iterate logs for i, l := range logs { refs, ok := refsMap[l.Hash] if ok { logs[i].Refs = refs } } return logs, nil } func (c *GitClient) GetRepository() (r *git.Repository) { return c.r } func (c *GitClient) GetPath() (path string) { return c.path } func (c *GitClient) SetPath(path string) { c.path = path } func (c *GitClient) GetRemoteUrl() (path string) { return c.remoteUrl } func (c *GitClient) SetRemoteUrl(url string) { c.remoteUrl = url } func (c *GitClient) GetIsMem() (isMem bool) { return c.isMem } func (c *GitClient) SetIsMem(isMem bool) { c.isMem = isMem } func (c *GitClient) GetAuthType() (authType GitAuthType) { return c.authType } func (c *GitClient) SetAuthType(authType GitAuthType) { c.authType = authType } func (c *GitClient) GetUsername() (username string) { return c.username } func (c *GitClient) SetUsername(username string) { c.username = username } func (c *GitClient) GetPassword() (password string) { return c.password } func (c *GitClient) SetPassword(password string) { c.password = password } func (c *GitClient) GetPrivateKey() (key string) { return c.privateKey } func (c *GitClient) SetPrivateKey(key string) { c.privateKey = key } func (c *GitClient) GetPrivateKeyPath() (path string) { return c.privateKeyPath } func (c *GitClient) SetPrivateKeyPath(path string) { c.privateKeyPath = path } func (c *GitClient) GetCurrentBranch() (branch string, err error) { // attempt to get branch from .git/HEAD headRefStr, err := c.getHeadRef() if err != nil { return "", err } // if .git/HEAD points to refs/heads/master, return branch as master if headRefStr == plumbing.Master.String() { return GitBranchNameMaster, nil } // attempt to get head ref headRef, err := c.r.Head() if err != nil { return "", trace.TraceError(err) } if !headRef.Name().IsBranch() { return "", trace.TraceError(ErrUnableToGetCurrentBranch) } return headRef.Name().Short(), nil } func (c *GitClient) GetCurrentBranchRef() (ref *GitRef, err error) { currentBranch, err := c.GetCurrentBranch() if err != nil { return nil, err } branches, err := c.GetBranches() if err != nil { return nil, err } for _, branch := range branches { if branch.Name == currentBranch { return &branch, nil } } return nil, trace.TraceError(ErrUnableToGetCurrentBranch) } func (c *GitClient) GetBranches() (branches []GitRef, err error) { iter, err := c.r.Branches() if err != nil { return nil, trace.TraceError(err) } _ = iter.ForEach(func(r *plumbing.Reference) error { branches = append(branches, GitRef{ Type: GitRefTypeBranch, Name: r.Name().Short(), Hash: r.Hash().String(), }) return nil }) return branches, nil } func (c *GitClient) GetRemoteRefs(remoteName string) (gitRefs []GitRef, err error) { if remoteName == "" { remoteName = GitRemoteNameOrigin } // remote r, err := c.r.Remote(remoteName) if err != nil { if errors.Is(err, git.ErrRemoteNotFound) { return nil, nil } return nil, trace.TraceError(err) } // auth auth, err := c.getGitAuth() if err != nil { return nil, err } // refs refs, err := r.List(&git.ListOptions{Auth: auth}) if err != nil { if !errors.Is(err, transport.ErrEmptyRemoteRepository) { return nil, trace.TraceError(err) } return nil, nil } // iterate refs for _, ref := range refs { // ref type var refType string var gitRef *GitRef if strings.HasPrefix(ref.Name().String(), "refs/heads") { refType = GitRefTypeBranch gitRef = &GitRef{ Type: refType, Name: remoteName + "/" + ref.Name().Short(), FullName: ref.Name().String(), Hash: ref.Hash().String(), } } else if strings.HasPrefix(ref.Name().String(), "refs/tags") { refType = GitRefTypeTag gitRef = &GitRef{ Type: refType, Name: ref.Name().Short(), FullName: ref.Name().String(), Hash: ref.Hash().String(), } } else { continue } gitRefs = append(gitRefs, *gitRef) } // logs without tags logs, err := c.GetLogs() if err != nil { return nil, err } // logs map logsMap := map[string]GitLog{} for _, l := range logs { logsMap[l.Hash] = l } // iterate git refs for i, gitRef := range gitRefs { l, ok := logsMap[gitRef.Hash] if !ok { continue } gitRefs[i].Timestamp = l.Timestamp } // sort git refs sort.Slice(gitRefs, func(i, j int) bool { return gitRefs[i].Timestamp.Unix() > gitRefs[j].Timestamp.Unix() }) return gitRefs, nil } func (c *GitClient) GetTags() (tags []GitRef, err error) { iter, err := c.r.Tags() if err != nil { return nil, trace.TraceError(err) } _ = iter.ForEach(func(r *plumbing.Reference) error { tags = append(tags, GitRef{ Type: GitRefTypeTag, Name: r.Name().Short(), Hash: r.Hash().String(), }) return nil }) return tags, nil } func (c *GitClient) GetStatus() (statusList []GitFileStatus, err error) { // worktree wt, err := c.r.Worktree() if err != nil { return nil, trace.TraceError(err) } // status status, err := wt.Status() if err != nil { log.Warnf("failed to get worktree status: %v", err) } // file status list var list []GitFileStatus for filePath, fileStatus := range status { // file name fileName := path.Base(filePath) // file status s := GitFileStatus{ Path: filePath, Name: fileName, IsDir: false, Staging: c.getStatusString(fileStatus.Staging), Worktree: c.getStatusString(fileStatus.Worktree), Extra: fileStatus.Extra, } // add to list list = append(list, s) } // sort list ascending sort.Slice(list, func(i, j int) bool { return list[i].Path < list[j].Path }) return list, nil } func (c *GitClient) Add(filePath string) (err error) { // worktree wt, err := c.r.Worktree() if err != nil { return trace.TraceError(err) } if _, err := wt.Add(filePath); err != nil { return trace.TraceError(err) } return nil } func (c *GitClient) GetRemote(name string) (r *git.Remote, err error) { return c.r.Remote(name) } func (c *GitClient) CreateRemote(cfg *config.RemoteConfig) (r *git.Remote, err error) { return c.r.CreateRemote(cfg) } func (c *GitClient) DeleteRemote(name string) (err error) { return c.r.DeleteRemote(name) } func (c *GitClient) IsRemoteChanged() (ok bool, err error) { return c.isRemoteChanged() } func (c *GitClient) initMem() (err error) { // validate options if !c.isMem || c.path == "" { return trace.TraceError(ErrInvalidOptions) } // get storage and worktree storage, wt := c.getMemStorageAndMemFs(c.path) // attempt to init c.r, err = git.Init(storage, wt) if err != nil { if errors.Is(err, git.ErrRepositoryAlreadyExists) { // if already exists, attempt to open c.r, err = git.Open(storage, wt) if err != nil { return trace.TraceError(err) } } else { return trace.TraceError(err) } } return nil } func (c *GitClient) initFs() (err error) { // validate options if c.path == "" { return trace.TraceError(ErrInvalidOptions) } // create directory if not exists _, err = os.Stat(c.path) if err != nil { if err := os.MkdirAll(c.path, os.ModePerm); err != nil { return trace.TraceError(err) } err = nil } // try to open repo c.r, err = git.PlainOpen(c.path) if err != nil { return err } return nil } func (c *GitClient) getInitType() (res GitInitType) { if c.isMem { return GitInitTypeMem } else { return GitInitTypeFs } } func (c *GitClient) createRemote(remoteName string, url string) (err error) { _, err = c.r.CreateRemote(&config.RemoteConfig{ Name: remoteName, URLs: []string{url}, }) if err != nil { return trace.TraceError(err) } return } func (c *GitClient) getMemStorageAndMemFs(key string) (storage *memory.Storage, fs billy.Filesystem) { // storage storageItem, ok := GitMemStorages.Load(key) if !ok { storage = memory.NewStorage() GitMemStorages.Store(key, storage) } else { switch storageItem.(type) { case *memory.Storage: storage = storageItem.(*memory.Storage) default: storage = memory.NewStorage() GitMemStorages.Store(key, storage) } } // file system fsItem, ok := GitMemFileSystem.Load(key) if !ok { fs = memfs.New() GitMemFileSystem.Store(key, fs) } else { switch fsItem.(type) { case billy.Filesystem: fs = fsItem.(billy.Filesystem) default: fs = memfs.New() GitMemFileSystem.Store(key, fs) } } return storage, fs } func (c *GitClient) getGitAuth() (auth transport.AuthMethod, err error) { switch c.authType { case GitAuthTypeNone: return nil, nil case GitAuthTypeHTTP: if c.username == "" && c.password == "" { return nil, nil } auth = &http.BasicAuth{ Username: c.username, Password: c.password, } return auth, nil case GitAuthTypeSSH: var privateKeyData []byte if c.privateKey != "" { // private key content privateKeyData = []byte(c.privateKey) } else if c.privateKeyPath != "" { // read from private key file privateKeyData, err = os.ReadFile(c.privateKeyPath) if err != nil { return nil, trace.TraceError(err) } } else { // no private key return nil, nil } signer, err := ssh.ParsePrivateKey(privateKeyData) if err != nil { return nil, trace.TraceError(err) } auth = &gitssh.PublicKeys{ User: c.username, Signer: signer, HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{ HostKeyCallback: ssh.InsecureIgnoreHostKey(), }, } return auth, nil default: return nil, trace.TraceError(ErrInvalidAuthType) } } func (c *GitClient) getHeadRef() (ref string, err error) { wt, err := c.r.Worktree() if err != nil { return "", trace.TraceError(err) } fh, err := wt.Filesystem.Open(path.Join(".git", "HEAD")) if err != nil { return "", trace.TraceError(err) } data, err := io.ReadAll(fh) if err != nil { return "", trace.TraceError(err) } m := headRefRegexp.FindStringSubmatch(string(data)) if len(m) < 2 { return "", trace.TraceError(ErrInvalidHeadRef) } return m[1], nil } func (c *GitClient) getStatusString(statusCode git.StatusCode) (code string) { return string(statusCode) //switch statusCode { //} //Unmodified StatusCode = ' ' //Untracked StatusCode = '?' //Modified StatusCode = 'M' //Added StatusCode = 'A' //Deleted StatusCode = 'D' //Renamed StatusCode = 'R' //Copied StatusCode = 'C' //UpdatedButUnmerged StatusCode = 'U' } func (c *GitClient) getDirPaths(filePath string) (paths []string) { pathItems := strings.Split(filePath, "/") var items []string for i, pathItem := range pathItems { if i == len(pathItems)-1 { continue } items = append(items, pathItem) dirPath := strings.Join(items, "/") paths = append(paths, dirPath) } return paths } func (c *GitClient) createBranch(branch, remote string, ref *plumbing.Reference) (err error) { // create a new branch if it does not exist cfg := config.Branch{ Name: branch, Remote: remote, } if err := c.r.CreateBranch(&cfg); err != nil { return err } // if ref is nil if ref == nil { // try to set to remote ref of branch first ref, err = c.getBranchHashRef(branch, remote) // if no matched remote branch, set to HEAD if errors.Is(err, ErrNoMatchedRemoteBranch) { ref, err = c.r.Head() if err != nil { return trace.TraceError(err) } } // error if err != nil { return trace.TraceError(err) } } // branch reference name branchRefName := plumbing.NewBranchReferenceName(branch) // branch reference branchRef := plumbing.NewHashReference(branchRefName, ref.Hash()) // set HEAD to branch reference if err := c.r.Storer.SetReference(branchRef); err != nil { return err } return nil } func (c *GitClient) getBranchHashRef(branch, remote string) (hashRef *plumbing.Reference, err error) { refs, err := c.GetRemoteRefs(remote) if err != nil { return nil, err } var branchRef *GitRef for _, r := range refs { if r.Name == branch { branchRef = &r break } } if branchRef == nil { return nil, ErrNoMatchedRemoteBranch } branchHashRef := plumbing.NewHashReference(plumbing.NewBranchReferenceName(branch), plumbing.NewHash(branchRef.Hash)) return branchHashRef, nil } func (c *GitClient) isRemoteChanged() (ok bool, err error) { b, err := c.GetCurrentBranchRef() if err != nil { return false, err } refs, err := c.GetRemoteRefs(GitRemoteNameOrigin) if err != nil { return false, err } for _, r := range refs { if r.Name == b.Name { return r.Hash != b.Hash, nil } } return false, nil } func NewGitClient(opts ...GitOption) (c *GitClient, err error) { // client c = &GitClient{ isMem: false, authType: GitAuthTypeNone, username: "git", privateKeyPath: getDefaultPublicKeyPath(), defaultInit: true, } // apply options for _, opt := range opts { opt(c) } // initialize if c.defaultInit { if err = c.Init(); err != nil { return nil, err } } return } ================================================ FILE: vcs/git_options.go ================================================ package vcs import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport" "strings" ) type GitOption func(c *GitClient) func WithPath(path string) GitOption { return func(c *GitClient) { c.path = path } } func WithRemoteUrl(url string) GitOption { return func(c *GitClient) { c.remoteUrl = url } } func WithIsMem() GitOption { return func(c *GitClient) { c.isMem = true } } func WithAuthType(authType GitAuthType) GitOption { return func(c *GitClient) { c.authType = authType } } func WithUsername(username string) GitOption { return func(c *GitClient) { c.username = username } } func WithPassword(password string) GitOption { return func(c *GitClient) { c.password = password } } func WithPrivateKey(key string) GitOption { return func(c *GitClient) { c.privateKey = key } } func WithDefaultInit(init bool) GitOption { return func(c *GitClient) { c.defaultInit = init } } func WithPrivateKeyPath(path string) GitOption { return func(c *GitClient) { c.privateKeyPath = path } } type GitCloneOption func(o *git.CloneOptions) func WithURL(url string) GitCloneOption { return func(o *git.CloneOptions) { o.URL = url } } type GitCheckoutOption func(o *git.CheckoutOptions) func WithBranch(branch string) GitCheckoutOption { return func(o *git.CheckoutOptions) { if strings.HasPrefix(branch, "refs/heads") { o.Branch = plumbing.ReferenceName(branch) } else { o.Branch = plumbing.NewBranchReferenceName(branch) } } } func WithHash(hash string) GitCheckoutOption { return func(o *git.CheckoutOptions) { h := plumbing.NewHash(hash) if h.IsZero() { return } o.Hash = h } } type GitCommitOption func(o *git.CommitOptions) type GitPullOption func(o *git.PullOptions) func WithRemoteNamePull(name string) GitPullOption { return func(o *git.PullOptions) { o.RemoteName = name } } func WithBranchNamePull(branch string) GitPullOption { return func(o *git.PullOptions) { o.ReferenceName = plumbing.NewBranchReferenceName(branch) } } func WithAuthPull(auth transport.AuthMethod) GitPullOption { return func(o *git.PullOptions) { if auth != nil { o.Auth = auth } } } type GitPushOption func(o *git.PushOptions) func WithAuthPush(auth transport.AuthMethod) GitPushOption { return func(o *git.PushOptions) { o.Auth = auth } } type GitResetOption func(o *git.ResetOptions) func WithMode(mode git.ResetMode) GitResetOption { return func(o *git.ResetOptions) { o.Mode = mode } } ================================================ FILE: vcs/git_store.go ================================================ package vcs import "sync" var GitMemStorages = sync.Map{} var GitMemFileSystem = sync.Map{} ================================================ FILE: vcs/git_utils.go ================================================ package vcs import ( "github.com/go-git/go-git/v5" "os" "path" ) func CreateBareGitRepo(path string) (err error) { // validate options if path == "" { return ErrInvalidRepoPath } // validate if exists if IsGitRepoExists(path) { return ErrRepoAlreadyExists } // create directory if not exists _, err = os.Stat(path) if err != nil { if err := os.MkdirAll(path, os.FileMode(0766)); err != nil { return err } err = nil } // init if _, err := git.PlainInit(path, true); err != nil { return err } return nil } func CloneGitRepo(path, url string, opts ...GitCloneOption) (c *GitClient, err error) { // url opts = append(opts, WithURL(url)) // apply options o := &git.CloneOptions{} for _, opt := range opts { opt(o) } // clone if _, err := git.PlainClone(path, false, o); err != nil { return nil, err } return NewGitClient(WithPath(path)) } func IsGitRepoExists(repoPath string) (ok bool) { dotGitPath := path.Join(repoPath, git.GitDirName) if _, err := os.Stat(dotGitPath); err == nil { return true } headPath := path.Join(repoPath, "HEAD") if _, err := os.Stat(headPath); err == nil { return true } return false } ================================================ FILE: vcs/go.mod ================================================ module github.com/crawlab-team/crawlab/vcs go 1.22 require ( github.com/apex/log v1.9.0 github.com/go-git/go-billy/v5 v5.5.0 github.com/go-git/go-git/v5 v5.12.0 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.23.0 ) require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/onsi/gomega v1.30.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/tools v0.20.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: vcs/go.sum ================================================ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 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 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/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 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/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 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/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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= 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.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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= ================================================ FILE: vcs/interface.go ================================================ package vcs type Client interface { Init() (err error) Dispose() (err error) Clone(opts ...GitCloneOption) (err error) Checkout(opts ...GitCheckoutOption) (err error) Commit(msg string, opts ...GitCommitOption) (err error) Pull(opts ...GitPullOption) (err error) Push(opts ...GitPushOption) (err error) Reset(opts ...GitResetOption) (err error) } ================================================ FILE: vcs/test/base.go ================================================ package test import ( vcs "github.com/crawlab-team/crawlab/vcs" "io/ioutil" "os" "path" "sync" "testing" "time" ) func init() { var err error T, err = NewTest() if err != nil { panic(err) } } var T *Test type Test struct { RemoteRepoPath string LocalRepoPath string LocalRepo *vcs.GitClient FsRepoPath string MemRepoPath string AuthRepoPath string AuthRepoPath1 string AuthRepoPath2 string AuthRepoPath3 string TestFileName string TestFileContent string TestBranchName string TestCommitMessage string InitialCommitMessage string InitialReadmeFileName string InitialReadmeFileContent string } func (t *Test) Setup(t2 *testing.T) { var err error t2.Cleanup(t.Cleanup) // remote repo if err := vcs.CreateBareGitRepo(t.RemoteRepoPath); err != nil { panic(err) } // local repo (fs) t.LocalRepo, err = vcs.NewGitClient( vcs.WithPath(t.LocalRepoPath), vcs.WithRemoteUrl(t.RemoteRepoPath), ) if err != nil { panic(err) } // initial commit filePath := path.Join(t.LocalRepoPath, t.InitialReadmeFileContent) if err := ioutil.WriteFile(filePath, []byte(t.InitialReadmeFileContent), os.FileMode(0766)); err != nil { panic(err) } if err := t.LocalRepo.CommitAll(t.InitialCommitMessage); err != nil { panic(err) } } func (t *Test) Cleanup() { if err := T.LocalRepo.Dispose(); err != nil { panic(err) } if err := os.RemoveAll(T.RemoteRepoPath); err != nil { panic(err) } vcs.GitMemStorages = sync.Map{} vcs.GitMemFileSystem = sync.Map{} // wait to avoid caching time.Sleep(500 * time.Millisecond) } func NewTest() (t *Test, err error) { t = &Test{} // clear tmp directory _ = os.RemoveAll("./tmp") _ = os.MkdirAll("./tmp", os.FileMode(0766)) // remote repo path t.RemoteRepoPath = "./tmp/test_remote_repo" // local repo path t.LocalRepoPath = "./tmp/test_local_repo" // fs repo path t.FsRepoPath = "./tmp/test_fs_repo" // mem repo path t.MemRepoPath = "./tmp/test_mem_repo" // auth repo path t.AuthRepoPath = "./tmp/test_auth_repo" // auth repo path 1 t.AuthRepoPath1 = "./tmp/test_auth_repo1" // auth repo path 2 t.AuthRepoPath2 = "./tmp/test_auth_repo2" // auth repo path 3 t.AuthRepoPath3 = "./tmp/test_auth_repo3" // test file name t.TestFileName = "test_file.txt" // test file content t.TestFileContent = "it works" // test branch name t.TestBranchName = "develop" // test commit message t.InitialCommitMessage = "test commit" // initial commit message t.InitialCommitMessage = "initial commit" // initial readme file name t.InitialReadmeFileName = "README.md" // initial readme file content t.InitialReadmeFileContent = "README" return t, nil } ================================================ FILE: vcs/test/credential.go ================================================ package test type Credential struct { Username string `json:"username"` Password string `json:"password"` TestRepoHttpUrl string `json:"test_repo_http_url"` TestRepoMultiBranchUrl string `json:"test_repo_multi_branch_url"` SshUsername string `json:"ssh_username"` SshPassword string `json:"ssh_password"` TestRepoSshUrl string `json:"test_repo_ssh_url"` PrivateKey string `json:"private_key"` PrivateKeyPath string `json:"private_key_path"` } ================================================ FILE: vcs/test/credentials.example.json ================================================ { "username": "changeit", "password": "changeit", "test_repo_http_url": "https://gitee.com/tikazyq/test-repo", "ssh_username": "git", "ssh_password": "", "test_repo_ssh_url": "git@gitee.com:tikazyq/test-repo.git", "private_key": "changeit", "private_key_path": "/root/.ssh/id_rsa" } ================================================ FILE: vcs/test/git_test.go ================================================ package test import ( "encoding/json" "fmt" "github.com/crawlab-team/crawlab/vcs" "github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/storage/memory" "github.com/stretchr/testify/require" "os" "path" "testing" "time" ) func TestNewGitClient_Existing(t *testing.T) { var err error T.Setup(t) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.LocalRepo.GetPath()), ) require.Nil(t, err) require.NotEmpty(t, c.GetRepository()) } func TestNewGitClient_Fs(t *testing.T) { var err error T.Setup(t) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.FsRepoPath), vcs.WithRemoteUrl(T.RemoteRepoPath), ) require.Nil(t, err) require.NotEmpty(t, c.GetRepository()) require.Equal(t, T.RemoteRepoPath, c.GetRemoteUrl()) } func TestNewGitClient_Mem(t *testing.T) { var err error T.Setup(t) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.MemRepoPath), vcs.WithRemoteUrl(T.RemoteRepoPath), vcs.WithIsMem(), ) require.Nil(t, err) require.NotEmpty(t, c.GetRepository()) } func TestGitClient_CommitAllAndCheckoutBranch(t *testing.T) { var err error T.Setup(t) // commit filePath := path.Join(T.LocalRepoPath, T.TestFileName) err = os.WriteFile(filePath, []byte(T.TestFileContent), os.FileMode(0766)) require.Nil(t, err) err = T.LocalRepo.CommitAll(T.TestCommitMessage) require.Nil(t, err) // checkout branch err = T.LocalRepo.CheckoutBranch(T.TestBranchName) require.Nil(t, err) // validate branch, err := T.LocalRepo.GetCurrentBranch() require.Nil(t, err) require.Equal(t, T.TestBranchName, branch) // dispose err = T.LocalRepo.Dispose() require.Nil(t, err) } func TestGitClient_Push(t *testing.T) { var err error T.Setup(t) // commit filePath := path.Join(T.LocalRepoPath, T.TestFileName) err = os.WriteFile(filePath, []byte(T.TestFileContent), os.FileMode(0766)) require.Nil(t, err) err = T.LocalRepo.CommitAll(T.TestCommitMessage) require.Nil(t, err) // push err = T.LocalRepo.Push() require.Nil(t, err) } func TestGitClient_Reset(t *testing.T) { var err error T.Setup(t) // file filePath := path.Join(T.LocalRepoPath, T.TestFileName) err = os.WriteFile(filePath, []byte(T.TestFileContent), os.FileMode(0766)) require.Nil(t, err) // reset err = T.LocalRepo.Reset(vcs.WithMode(git.HardReset)) // git reset --hard require.Nil(t, err) _, err = os.Stat(filePath) require.IsType(t, &os.PathError{}, err) } func TestGitClient_GetLogs(t *testing.T) { var err error T.Setup(t) // file filePath := path.Join(T.LocalRepoPath, T.TestFileName) err = os.WriteFile(filePath, []byte(T.TestFileContent), os.FileMode(0766)) require.Nil(t, err) err = T.LocalRepo.CommitAll(T.TestCommitMessage) require.Nil(t, err) // get logs logs, err := T.LocalRepo.GetLogs() require.Nil(t, err) require.Greater(t, len(logs), 0) require.Equal(t, T.TestCommitMessage, logs[0].Msg) } func TestGitClient_InitWithHttpAuth(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // create new git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoHttpUrl), vcs.WithAuthType(vcs.GitAuthTypeHTTP), vcs.WithUsername(cred.Username), vcs.WithPassword(cred.Password), ) require.Nil(t, err) require.Equal(t, cred.TestRepoHttpUrl, c.GetRemoteUrl()) require.Equal(t, vcs.GitAuthTypeHTTP, c.GetAuthType()) require.Equal(t, cred.Username, c.GetUsername()) // pull err = c.Pull() require.Nil(t, err) // validate files, err := os.ReadDir(T.AuthRepoPath) require.Greater(t, len(files), 0) data, err = os.ReadFile(path.Join(T.AuthRepoPath, "README.md")) require.Nil(t, err) // dispose err = c.Dispose() require.Nil(t, err) } func TestGitClient_MoveBranch(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // create new git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoHttpUrl), vcs.WithAuthType(vcs.GitAuthTypeHTTP), vcs.WithUsername(cred.Username), vcs.WithPassword(cred.Password), ) require.Nil(t, err) // pull err = c.Pull(vcs.WithBranchNamePull(vcs.GitBranchNameMain)) require.Nil(t, err) // move branch err = c.MoveBranch(vcs.GitBranchNameMaster, vcs.GitBranchNameMain) require.Nil(t, err) // validate var branchNames []string branches, err := c.GetBranches() require.Nil(t, err) for _, b := range branches { branchNames = append(branchNames, b.Name) } require.Contains(t, branchNames, vcs.GitBranchNameMain) require.NotContains(t, branchNames, vcs.GitBranchNameMaster) } func TestGitClient_PullWithHttpAuth(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // create new git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoHttpUrl), vcs.WithAuthType(vcs.GitAuthTypeHTTP), vcs.WithUsername(cred.Username), vcs.WithPassword(cred.Password), ) require.Nil(t, err) // create remote r, err := c.CreateRemote(&config.RemoteConfig{ Name: vcs.GitRemoteNameUpstream, URLs: []string{cred.TestRepoHttpUrl}, }) require.Nil(t, err) require.NotNil(t, r) // pull err = c.Pull( vcs.WithRemoteNamePull(vcs.GitRemoteNameUpstream), vcs.WithBranchNamePull(vcs.GitBranchNameMain), ) require.Nil(t, err) // validate files, err := os.ReadDir(T.AuthRepoPath) require.Greater(t, len(files), 0) data, err = os.ReadFile(path.Join(T.AuthRepoPath, "README.md")) require.Nil(t, err) // dispose err = c.Dispose() require.Nil(t, err) } func TestGitClient_CheckoutRemoteBranchWithHttpAuth(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // create new git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoMultiBranchUrl), vcs.WithAuthType(vcs.GitAuthTypeHTTP), vcs.WithUsername(cred.Username), vcs.WithPassword(cred.Password), ) require.Nil(t, err) // pull err = c.Pull( vcs.WithRemoteNamePull(vcs.GitRemoteNameOrigin), vcs.WithBranchNamePull(vcs.GitBranchNameMain), ) require.Nil(t, err) // validate _, err = os.ReadFile(path.Join(T.AuthRepoPath, "MAIN")) require.Nil(t, err) // checkout remote branch err = c.CheckoutBranchWithRemote(vcs.GitBranchNameRelease, vcs.GitRemoteNameOrigin, nil) require.Nil(t, err) // validate _, err = os.ReadFile(path.Join(T.AuthRepoPath, "RELEASE")) require.Nil(t, err) // checkout remote branch err = c.CheckoutBranchWithRemote(vcs.GitBranchNameDevelop, vcs.GitRemoteNameOrigin, nil) require.Nil(t, err) // validate _, err = os.ReadFile(path.Join(T.AuthRepoPath, "DEVELOP")) require.Nil(t, err) // dispose err = c.Dispose() require.Nil(t, err) } func TestGitClient_InitWithSshAuth_PrivateKey(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) fmt.Println(cred.SshUsername) fmt.Println(cred.SshPassword) fmt.Println(cred.TestRepoSshUrl) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoSshUrl), vcs.WithAuthType(vcs.GitAuthTypeSSH), vcs.WithUsername(cred.SshUsername), vcs.WithPassword(cred.SshPassword), vcs.WithPrivateKey(cred.PrivateKey), ) require.Nil(t, err) require.Equal(t, cred.TestRepoSshUrl, c.GetRemoteUrl()) require.Equal(t, vcs.GitAuthTypeSSH, c.GetAuthType()) require.Equal(t, cred.SshUsername, c.GetUsername()) fmt.Println(c.GetAuthType()) // pull err = c.Pull() require.Nil(t, err) // validate files, err := os.ReadDir(T.AuthRepoPath) require.Greater(t, len(files), 0) data, err = os.ReadFile(path.Join(T.AuthRepoPath, "README.md")) require.Nil(t, err) // dispose err = c.Dispose() require.Nil(t, err) } func TestGitClient_InitWithSshAuth_PrivateKeyPath(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath), vcs.WithRemoteUrl(cred.TestRepoSshUrl), vcs.WithAuthType(vcs.GitAuthTypeSSH), vcs.WithUsername(cred.SshUsername), vcs.WithPassword(cred.SshPassword), vcs.WithPrivateKeyPath(cred.PrivateKeyPath), ) require.Nil(t, err) require.Equal(t, cred.TestRepoSshUrl, c.GetRemoteUrl()) require.Equal(t, vcs.GitAuthTypeSSH, c.GetAuthType()) require.Equal(t, cred.SshUsername, c.GetUsername()) require.Equal(t, cred.PrivateKeyPath, c.GetPrivateKeyPath()) // pull err = c.Pull() require.Nil(t, err) // validate files, err := os.ReadDir(T.AuthRepoPath) require.Greater(t, len(files), 0) data, err = os.ReadFile(path.Join(T.AuthRepoPath, "README.md")) require.Nil(t, err) } func TestGitClient_Dispose_Fs(t *testing.T) { var err error T.Setup(t) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.FsRepoPath), vcs.WithRemoteUrl(T.RemoteRepoPath), ) require.Nil(t, err) // path exists require.DirExists(t, T.FsRepoPath) // dispose err = c.Dispose() require.Nil(t, err) // validate _, err = os.Stat(T.FsRepoPath) require.IsType(t, &os.PathError{}, err) } func TestGitClient_Dispose_Mem(t *testing.T) { var err error T.Setup(t) // git client c, err := vcs.NewGitClient( vcs.WithPath(T.MemRepoPath), vcs.WithRemoteUrl(T.RemoteRepoPath), vcs.WithIsMem(), ) require.Nil(t, err) // mem map exists stItem, ok := vcs.GitMemStorages.Load(T.MemRepoPath) require.True(t, ok) require.IsType(t, &memory.Storage{}, stItem) fsItem, ok := vcs.GitMemFileSystem.Load(T.MemRepoPath) require.True(t, ok) require.IsType(t, memfs.New(), fsItem) // dispose err = c.Dispose() require.Nil(t, err) // validate _, ok = vcs.GitMemStorages.Load("./tmp/test_repo") require.False(t, ok) _, ok = vcs.GitMemFileSystem.Load("./tmp/test_repo") require.False(t, ok) } func TestGitClient_IsRemoteChanged(t *testing.T) { var err error T.Setup(t) // get credentials var cred Credential data, err := os.ReadFile("credentials.json") require.Nil(t, err) err = json.Unmarshal(data, &cred) require.Nil(t, err) // git client c1, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath1), vcs.WithRemoteUrl(cred.TestRepoSshUrl), vcs.WithAuthType(vcs.GitAuthTypeSSH), vcs.WithUsername(cred.SshUsername), vcs.WithPassword(cred.SshPassword), vcs.WithPrivateKeyPath(cred.PrivateKeyPath), ) require.Nil(t, err) err = c1.Pull() require.Nil(t, err) err = c1.CheckoutBranch("main") require.Nil(t, err) // git client (for validation) c2, err := vcs.NewGitClient( vcs.WithPath(T.AuthRepoPath2), vcs.WithRemoteUrl(cred.TestRepoSshUrl), vcs.WithAuthType(vcs.GitAuthTypeSSH), vcs.WithUsername(cred.SshUsername), vcs.WithPassword(cred.SshPassword), vcs.WithPrivateKeyPath(cred.PrivateKeyPath), ) require.Nil(t, err) err = c2.Pull() require.Nil(t, err) err = c2.CheckoutBranch("main") require.Nil(t, err) // commit and push testFileName := fmt.Sprintf("test-%d.txt", time.Now().Unix()) filePath := path.Join(c1.GetPath(), testFileName) err = os.WriteFile(filePath, []byte(T.TestFileContent), os.FileMode(0766)) require.Nil(t, err) err = c1.Add(testFileName) require.Nil(t, err) err = c1.CommitAll(fmt.Sprintf("added %s", testFileName)) require.Nil(t, err) err = c1.Push() require.Nil(t, err) // validate ok, err := c2.IsRemoteChanged() require.Nil(t, err) require.True(t, ok) // pull and validate err = c2.Pull() require.Nil(t, err) ok, err = c2.IsRemoteChanged() require.Nil(t, err) require.False(t, ok) } ================================================ FILE: vcs/utils.go ================================================ package vcs import ( "os/user" "path/filepath" ) func getDefaultPublicKeyPath() (path string) { u, err := user.Current() if err != nil { return path } path = filepath.Join(u.HomeDir, ".ssh", "id_rsa") return } ================================================ FILE: workspace/.gitignore ================================================ data/ ================================================ FILE: workspace/docker-compose.yml ================================================ version: '3.3' services: build: build: context: ./dockerfiles/golang command: /bin/bash -c "rm -f /backend/dist/crawlab && go build -o ./dist/crawlab ./" volumes: - ./dist:/backend/dist - ./.crawlab/go/pkg/mod:/go/pkg/mod - ../backend:/backend - ../backend/go.mod.local:/backend/go.mod - ../..:/libs/crawlab-team environment: GOPROXY: https://goproxy.cn,direct master: build: context: ./dockerfiles/golang command: /bin/bash -c "/app/bin/docker-start-master.sh && /dist/crawlab master" volumes: - ./dist:/dist - ./.crawlab/master:/root/.crawlab - ./.crawlab/go/pkg/mod:/go/pkg/mod - ../backend:/backend - ../backend/go.mod.local:/backend/go.mod - ../..:/libs/crawlab-team - ../bin:/app/bin - ../nginx:/etc/nginx/conf.d - ../frontend/dist:/app/dist environment: CRAWLAB_NODE_MASTER: "Y" CRAWLAB_NODE_NAME: "Master Node" CRAWLAB_MONGO_HOST: "mongo" CRAWLAB_LOG_LEVEL: debug GOPROXY: https://goproxy.cn,direct ports: - "9080:8080" - "9000:8000" - "9866:9666" - "9888:8888" depends_on: - mongo worker01: build: context: ./dockerfiles/golang command: /bin/bash -c "/dist/crawlab worker" environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_NODE_NAME: "Worker Node 01" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" CRAWLAB_LOG_LEVEL: debug GOPROXY: https://goproxy.cn,direct volumes: - ./dist:/dist - ./.crawlab/worker01:/root/.crawlab - ./.crawlab/go/pkg/mod:/go/pkg/mod - ../backend:/backend - ../backend/go.mod.local:/backend/go.mod - ../..:/libs/crawlab-team depends_on: - master worker02: build: context: ./dockerfiles/golang command: /bin/bash -c "/dist/crawlab worker" environment: CRAWLAB_NODE_MASTER: "N" CRAWLAB_NODE_NAME: "Worker Node 02" CRAWLAB_GRPC_ADDRESS: "master" CRAWLAB_FS_FILER_URL: "http://master:8080/api/filer" CRAWLAB_LOG_LEVEL: debug GOPROXY: https://goproxy.cn,direct volumes: - ./dist:/dist - ./.crawlab/worker02:/root/.crawlab - ./.crawlab/go/pkg/mod:/go/pkg/mod - ../backend:/backend - ../backend/go.mod.local:/backend/go.mod - ../..:/libs/crawlab-team depends_on: - master - worker01 mongo: image: mongo:4 restart: always ports: - "28017:27017" ================================================ FILE: workspace/dockerfiles/golang/Dockerfile ================================================ FROM golang:1.16 RUN go env -w GOPROXY=https://goproxy.io,https://goproxy.cn && \ go env -w GO111MODULE="on" WORKDIR /tools RUN go get github.com/cosmtrek/air WORKDIR /backend RUN rm -rf /tools # set as non-interactive ENV DEBIAN_FRONTEND noninteractive # install packages RUN chmod 777 /tmp \ && apt-get update \ && apt-get install -y curl git net-tools iputils-ping ntp ntpdate nginx wget dumb-init cloc # install python RUN apt-get install -y python3 python3-pip \ && ln -s /usr/bin/pip3 /usr/local/bin/pip \ && ln -s /usr/bin/python3 /usr/local/bin/python # install golang RUN curl -OL https://storage.googleapis.com/golang/go1.16.7.linux-amd64.tar.gz \ && tar -C /usr/local -xvf go1.16.7.linux-amd64.tar.gz \ && ln -s /usr/local/go/bin/go /usr/local/bin/go \ && rm go1.16.7.linux-amd64.tar.gz # install seaweedfs RUN wget https://github.com/chrislusf/seaweedfs/releases/download/2.76/linux_amd64.tar.gz \ && tar -zxf linux_amd64.tar.gz \ && cp weed /usr/local/bin \ && rm linux_amd64.tar.gz # install backend RUN pip install scrapy pymongo bs4 requests -i https://mirrors.aliyun.com/pypi/simple RUN pip install crawlab-sdk==0.6.b20211024-1207 VOLUME /backend EXPOSE 8080 ================================================ FILE: workspace/dockerfiles/node/.dockerignore ================================================ **/node_modules/ ================================================ FILE: workspace/dockerfiles/node/Dockerfile ================================================ FROM node:12 WORKDIR frontend ENV SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ RUN npm config set registry "http://registry.npm.taobao.org" ================================================ FILE: workspace/localdev/README.md ================================================ # Local Dev For those who want to develop or contribute to crawlab project can use `docker-compose.yml` to start necessary containers (fs, mongo) to support local development. Please make sure you have installed [Docker](https://docker.io) and [Docker-Compose](https://docs.docker.com/compose/). ## Start Containers ```bash docker-compose up -d ``` ## Stop Containers ```bash docker-compose down ``` ================================================ FILE: workspace/localdev/docker-compose.yml ================================================ version: '2' services: fs: image: chrislusf/seaweedfs:2.79 # use a remote image container_name: crawlab_localdev_fs restart: always # command: "server -dir /data -master.dir /data -volume.dir.idx /data -ip localhost -ip.bind 0.0.0.0 -filer -encryptVolumeData" # auth command: "server -dir /data -master.dir /data -volume.dir.idx /data -ip localhost -ip.bind 0.0.0.0 -filer" # no auth ports: - 8080:8080 - 8888:8888 - 9333:9333 - 7333:7333 volumes: - ./data/fs:/data mongo: image: mongo:5 container_name: crawlab_localdev_mongo restart: always ports: - 27017:27017 volumes: - ./data/mongo:/data mysql: platform: linux/x86_64 image: mysql:8 container_name: crawlab_local_dev_mysql restart: always command: --default-authentication-plugin=mysql_native_password ports: - 3306:3306 volumes: - ./data/mysql:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: crawlab MYSQL_DATABASE: crawlab MYSQL_USER: crawlab MYSQL_PASSWORD: crawlab