From 55cea9e91253a00ee7510486872978b99aee596b Mon Sep 17 00:00:00 2001 From: ytwp Date: Mon, 26 Feb 2024 10:19:42 +0800 Subject: [PATCH] [Feature] New Web UI --- docs/security.md | 12 +- gateway-ha/pom.xml | 75 +- .../trino/gateway/ha/HaGatewayLauncher.java | 5 +- .../ha/config/HaGatewayConfiguration.java | 13 +- .../gateway/ha/config/OAuthConfiguration.java | 11 + .../java/io/trino/gateway/ha/domain/R.java | 176 + .../io/trino/gateway/ha/domain/TableData.java | 73 + .../domain/request/GlobalPropertyRequest.java | 48 + .../request/QueryDistributionRequest.java | 35 + .../request/QueryGlobalPropertyRequest.java | 50 + .../domain/request/QueryHistoryRequest.java | 96 + .../request/QueryResourceGroupsRequest.java | 50 + .../domain/request/QuerySelectorsRequest.java | 50 + .../domain/request/ResourceGroupsRequest.java | 48 + .../ha/domain/request/RestLoginRequest.java | 43 + .../ha/domain/request/SelectorsRequest.java | 67 + .../ha/domain/response/BackendResponse.java | 46 + .../domain/response/DistributionResponse.java | 233 + .../ha/module/HaGatewayProviderModule.java | 6 +- .../ha/persistence/dao/QueryHistoryDao.java | 30 + .../ha/resource/EntityEditorResource.java | 62 - .../ha/resource/GatewayViewResource.java | 165 +- .../ha/resource/GatewayWebAppResource.java | 415 + .../gateway/ha/resource/LoginResource.java | 98 +- .../ha/router/HaQueryHistoryManager.java | 49 + .../ha/router/QueryHistoryManager.java | 8 + .../security/AuthorizedExceptionMapper.java | 35 + .../ha/security/LbFormAuthManager.java | 45 +- .../gateway/ha/security/LbOAuthManager.java | 31 +- .../ha/security/NoopAuthenticator.java | 3 +- .../io/trino/gateway/ha/util/PageUtil.java | 36 + .../src/main/resources/assets/css/common.css | 28 - .../assets/css/jquery.dataTables.min.css | 1 - .../src/main/resources/assets/img/favicon.ico | Bin 32038 -> 0 bytes .../main/resources/assets/js/entity-editor.js | 139 - .../main/resources/assets/js/hbar-chart.js | 107 - .../main/resources/assets/js/jquery-3.3.1.js | 10364 ----- .../assets/js/jquery.dataTables.min.js | 166 - .../js/jsonedit/img/jsoneditor-icons.svg | 893 - .../assets/js/jsonedit/jsoneditor.css | 929 - .../assets/js/jsonedit/jsoneditor.js | 36354 ---------------- .../assets/js/jsonedit/jsoneditor.map | 1 - .../assets/js/jsonedit/jsoneditor.min.css | 1 - .../assets/js/jsonedit/jsoneditor.min.js | 49 - .../main/resources/template/entity-view.ftl | 32 - .../src/main/resources/template/footer.ftl | 3 - .../main/resources/template/gateway-view.ftl | 93 - .../src/main/resources/template/header.ftl | 22 - .../main/resources/template/login-form.ftl | 51 - .../resources/template/query-history-view.ftl | 99 - .../ha/security/TestLbAuthenticator.java | 26 +- webapp/.env | 4 + webapp/.env.development | 4 + webapp/.env.production | 3 + webapp/.eslintrc.cjs | 20 + webapp/.gitignore | 26 + webapp/README.md | 26 + webapp/index.html | 13 + webapp/package.json | 41 + webapp/pnpm-lock.yaml | 3265 ++ webapp/public/logo.svg | 121 + webapp/src/App.tsx | 117 + webapp/src/api/base.ts | 138 + webapp/src/api/webapp/cluster.ts | 18 + webapp/src/api/webapp/dashboard.ts | 6 + webapp/src/api/webapp/global-property.ts | 21 + webapp/src/api/webapp/history.ts | 6 + webapp/src/api/webapp/login.ts | 21 + webapp/src/api/webapp/resource-group.ts | 22 + webapp/src/api/webapp/selector.ts | 22 + webapp/src/assets/logo.svg | 121 + webapp/src/components/cluster.module.scss | 8 + webapp/src/components/cluster.tsx | 211 + webapp/src/components/dashboard.module.scss | 26 + webapp/src/components/dashboard.tsx | 248 + webapp/src/components/error.tsx | 40 + webapp/src/components/history.module.scss | 8 + webapp/src/components/history.tsx | 122 + webapp/src/components/layout.module.scss | 181 + webapp/src/components/layout.tsx | 201 + webapp/src/components/login.module.scss | 104 + webapp/src/components/login.tsx | 130 + .../src/components/resource-group.module.scss | 8 + webapp/src/components/resource-group.tsx | 283 + webapp/src/components/selector.module.scss | 8 + webapp/src/components/selector.tsx | 208 + webapp/src/constant.ts | 4 + webapp/src/locales/en_US.ts | 81 + webapp/src/locales/index.ts | 93 + webapp/src/main.tsx | 9 + webapp/src/router.tsx | 121 + webapp/src/store/access.ts | 96 + webapp/src/store/config.ts | 55 + webapp/src/store/index.ts | 2 + webapp/src/styles/animation.scss | 23 + webapp/src/styles/globals.scss | 42 + webapp/src/types/cluster.d.ts | 9 + webapp/src/types/dashboard.d.ts | 24 + webapp/src/types/history.d.ts | 13 + webapp/src/types/resource-group.d.ts | 15 + webapp/src/types/selector.d.ts | 9 + webapp/src/utils/merge.ts | 9 + webapp/src/utils/time.ts | 41 + webapp/src/utils/token.ts | 22 + webapp/src/utils/utils.ts | 171 + webapp/src/vite-env.d.ts | 2 + webapp/tsconfig.json | 25 + webapp/tsconfig.node.json | 10 + webapp/vite.config.ts | 24 + 109 files changed, 8545 insertions(+), 49628 deletions(-) create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/R.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/TableData.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/GlobalPropertyRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryDistributionRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryGlobalPropertyRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryHistoryRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryResourceGroupsRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QuerySelectorsRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/ResourceGroupsRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/RestLoginRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/SelectorsRequest.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/BackendResponse.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/DistributionResponse.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/security/AuthorizedExceptionMapper.java create mode 100644 gateway-ha/src/main/java/io/trino/gateway/ha/util/PageUtil.java delete mode 100644 gateway-ha/src/main/resources/assets/css/common.css delete mode 100644 gateway-ha/src/main/resources/assets/css/jquery.dataTables.min.css delete mode 100644 gateway-ha/src/main/resources/assets/img/favicon.ico delete mode 100644 gateway-ha/src/main/resources/assets/js/entity-editor.js delete mode 100644 gateway-ha/src/main/resources/assets/js/hbar-chart.js delete mode 100644 gateway-ha/src/main/resources/assets/js/jquery-3.3.1.js delete mode 100644 gateway-ha/src/main/resources/assets/js/jquery.dataTables.min.js delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/img/jsoneditor-icons.svg delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/jsoneditor.css delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/jsoneditor.js delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/jsoneditor.map delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/jsoneditor.min.css delete mode 100644 gateway-ha/src/main/resources/assets/js/jsonedit/jsoneditor.min.js delete mode 100644 gateway-ha/src/main/resources/template/entity-view.ftl delete mode 100644 gateway-ha/src/main/resources/template/footer.ftl delete mode 100644 gateway-ha/src/main/resources/template/gateway-view.ftl delete mode 100644 gateway-ha/src/main/resources/template/header.ftl delete mode 100644 gateway-ha/src/main/resources/template/login-form.ftl delete mode 100644 gateway-ha/src/main/resources/template/query-history-view.ftl create mode 100644 webapp/.env create mode 100644 webapp/.env.development create mode 100644 webapp/.env.production create mode 100644 webapp/.eslintrc.cjs create mode 100644 webapp/.gitignore create mode 100644 webapp/README.md create mode 100644 webapp/index.html create mode 100644 webapp/package.json create mode 100644 webapp/pnpm-lock.yaml create mode 100644 webapp/public/logo.svg create mode 100644 webapp/src/App.tsx create mode 100644 webapp/src/api/base.ts create mode 100644 webapp/src/api/webapp/cluster.ts create mode 100644 webapp/src/api/webapp/dashboard.ts create mode 100644 webapp/src/api/webapp/global-property.ts create mode 100644 webapp/src/api/webapp/history.ts create mode 100644 webapp/src/api/webapp/login.ts create mode 100644 webapp/src/api/webapp/resource-group.ts create mode 100644 webapp/src/api/webapp/selector.ts create mode 100644 webapp/src/assets/logo.svg create mode 100644 webapp/src/components/cluster.module.scss create mode 100644 webapp/src/components/cluster.tsx create mode 100644 webapp/src/components/dashboard.module.scss create mode 100644 webapp/src/components/dashboard.tsx create mode 100644 webapp/src/components/error.tsx create mode 100644 webapp/src/components/history.module.scss create mode 100644 webapp/src/components/history.tsx create mode 100644 webapp/src/components/layout.module.scss create mode 100644 webapp/src/components/layout.tsx create mode 100644 webapp/src/components/login.module.scss create mode 100644 webapp/src/components/login.tsx create mode 100644 webapp/src/components/resource-group.module.scss create mode 100644 webapp/src/components/resource-group.tsx create mode 100644 webapp/src/components/selector.module.scss create mode 100644 webapp/src/components/selector.tsx create mode 100644 webapp/src/constant.ts create mode 100644 webapp/src/locales/en_US.ts create mode 100644 webapp/src/locales/index.ts create mode 100644 webapp/src/main.tsx create mode 100644 webapp/src/router.tsx create mode 100644 webapp/src/store/access.ts create mode 100644 webapp/src/store/config.ts create mode 100644 webapp/src/store/index.ts create mode 100644 webapp/src/styles/animation.scss create mode 100644 webapp/src/styles/globals.scss create mode 100644 webapp/src/types/cluster.d.ts create mode 100644 webapp/src/types/dashboard.d.ts create mode 100644 webapp/src/types/history.d.ts create mode 100644 webapp/src/types/resource-group.d.ts create mode 100644 webapp/src/types/selector.d.ts create mode 100644 webapp/src/utils/merge.ts create mode 100644 webapp/src/utils/time.ts create mode 100644 webapp/src/utils/token.ts create mode 100644 webapp/src/utils/utils.ts create mode 100644 webapp/src/vite-env.d.ts create mode 100644 webapp/tsconfig.json create mode 100644 webapp/tsconfig.node.json create mode 100644 webapp/vite.config.ts diff --git a/docs/security.md b/docs/security.md index 3860441cf..d6a63417d 100644 --- a/docs/security.md +++ b/docs/security.md @@ -60,6 +60,7 @@ authentication: authorizationEndpoint: jwkEndpoint: redirectUrl: + redirectWebUrl: userIdField: scopes: - s1 @@ -89,15 +90,16 @@ authentication: The authentication happens with the pre-defined users from the configuration file. To define the preset user use the following section. +Please note that 'privileges' can only be a combination of 'ADMIN', 'USER', and 'API', with '_' used for segmentation. ``` presetUsers: user1: password: - privileges: "lb_admin, lb_user" + privileges: ADMIN_USER user2: password: - privileges: "lb_api" + privileges: API ``` Also provide a random key pair in RSA format. @@ -146,9 +148,9 @@ LDAP Authorization is also supported by adding user attribute configs in file. ``` # Roles should be in regex format authorization: - admin: 'lb_admin' - user: 'lb_user' - api: 'lb_api' + admin: (.*)ADMIN(.*) + user: (.*)USER(.*) + api: (.*)API(.*) ldapConfigPath: '' ``` diff --git a/gateway-ha/pom.xml b/gateway-ha/pom.xml index 18f11084e..cba2fdf3f 100644 --- a/gateway-ha/pom.xml +++ b/gateway-ha/pom.xml @@ -17,6 +17,7 @@ development io.trino.gateway.ha.HaGatewayLauncher + webapp 2.3 @@ -208,11 +209,6 @@ - - io.dropwizard - dropwizard-views - - io.dropwizard.metrics metrics-core @@ -239,6 +235,11 @@ jakarta.ws.rs-api + + org.apache.commons + commons-lang3 + + org.apache.commons commons-pool2 @@ -552,6 +553,69 @@ + + org.apache.maven.plugins + maven-resources-plugin + + + copy static + + copy-resources + + generate-resources + + src/main/resources/static + true + + + ${project.basedir}/../${frontend.project.name}/dist + + + + + + + + + com.github.eirslett + frontend-maven-plugin + 1.12.1 + + ${project.basedir}/../${frontend.project.name} + + + + install node and pnpm + + install-node-and-pnpm + + + v18.9.1 + 8.6.12 + + + + install + + pnpm + + generate-resources + + install --ignore-scripts + + + + build + + pnpm + + + run build + + + + + org.javalite db-migrator-maven-plugin @@ -570,4 +634,5 @@ + diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/HaGatewayLauncher.java b/gateway-ha/src/main/java/io/trino/gateway/ha/HaGatewayLauncher.java index 90ec80044..9df16593b 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/HaGatewayLauncher.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/HaGatewayLauncher.java @@ -15,7 +15,6 @@ import io.dropwizard.assets.AssetsBundle; import io.dropwizard.core.setup.Bootstrap; -import io.dropwizard.views.common.ViewBundle; import io.trino.gateway.baseapp.BaseApp; import io.trino.gateway.ha.config.HaGatewayConfiguration; @@ -31,8 +30,8 @@ public HaGatewayLauncher(String... basePackages) public void initialize(Bootstrap bootstrap) { super.initialize(bootstrap); - bootstrap.addBundle(new ViewBundle<>()); - bootstrap.addBundle(new AssetsBundle("/assets", "/assets", null, "assets")); + bootstrap.addBundle(new AssetsBundle("/static/assets", "/assets", null, "assets")); + bootstrap.addBundle(new AssetsBundle("/static", "/logo.svg", "logo.svg", "logo.svg")); } public static void main(String[] args) diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/config/HaGatewayConfiguration.java b/gateway-ha/src/main/java/io/trino/gateway/ha/config/HaGatewayConfiguration.java index 44f958dbc..2a4fabc32 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/config/HaGatewayConfiguration.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/config/HaGatewayConfiguration.java @@ -30,7 +30,8 @@ public class HaGatewayConfiguration private RoutingRulesConfiguration routingRules = new RoutingRulesConfiguration(); private AuthenticationConfiguration authentication; private AuthorizationConfiguration authorization; - private Map presetUsers = new HashMap(); + private Map presetUsers = new HashMap<>(); + private Map pagePermissions = new HashMap<>(); private BackendStateConfiguration backendState; private ClusterStatsConfiguration clusterStatsConfiguration; private List extraWhitelistPaths = new ArrayList<>(); @@ -117,6 +118,16 @@ public void setPresetUsers(Map presetUsers) this.presetUsers = presetUsers; } + public Map getPagePermissions() + { + return this.pagePermissions; + } + + public void setPagePermissions(Map pagePermissions) + { + this.pagePermissions = pagePermissions; + } + public BackendStateConfiguration getBackendState() { return this.backendState; diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/config/OAuthConfiguration.java b/gateway-ha/src/main/java/io/trino/gateway/ha/config/OAuthConfiguration.java index 942bcaeca..a65f1d83b 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/config/OAuthConfiguration.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/config/OAuthConfiguration.java @@ -27,6 +27,7 @@ public class OAuthConfiguration private String redirectUrl; private String userIdField; private List audiences; + private String redirectWebUrl; public OAuthConfiguration(String issuer, String clientId, String clientSecret, String tokenEndpoint, String authorizationEndpoint, String jwkEndpoint, List scopes, String redirectUrl, String userIdField, List audiences) { @@ -143,4 +144,14 @@ public void setAudiences(List audiences) { this.audiences = audiences; } + + public String getRedirectWebUrl() + { + return this.redirectWebUrl; + } + + public void setRedirectWebUrl(String redirectWebUrl) + { + this.redirectWebUrl = redirectWebUrl; + } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/R.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/R.java new file mode 100644 index 000000000..3f209a2b2 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/R.java @@ -0,0 +1,176 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain; + +import jakarta.ws.rs.core.Response; + +import java.io.Serial; +import java.io.Serializable; + +/** + * Response + */ +public class R + implements Serializable +{ + @Serial + private static final long serialVersionUID = 1L; + + /** + * success + */ + public static final int SUCCESS = 200; + + /** + * fail + */ + public static final int FAIL = 500; + + /** + * warn + */ + public static final int WARN = 601; + + private int code; + + private String msg; + + private T data; + + public static R ok() + { + return restResult(null, SUCCESS, "Successful."); + } + + public static R ok(T data) + { + return restResult(data, SUCCESS, "Successful."); + } + + public static R ok(String msg) + { + return restResult(null, SUCCESS, msg); + } + + public static R ok(String msg, T data) + { + return restResult(data, SUCCESS, msg); + } + + public static R fail() + { + return restResult(null, FAIL, "Failed."); + } + + public static R fail(String msg) + { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) + { + return restResult(data, FAIL, "Failed."); + } + + public static R fail(String msg, T data) + { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) + { + return restResult(null, code, msg); + } + + public static R fail(Response.Status status) + { + return restResult(null, status.getStatusCode(), status.getReasonPhrase()); + } + + /** + * return warn message + * + * @param msg return message + * @return R + */ + public static R warn(String msg) + { + return restResult(null, WARN, msg); + } + + /** + * return warn message + * + * @param msg return message + * @param data return data + * @return R + */ + public static R warn(String msg, T data) + { + return restResult(data, WARN, msg); + } + + private static R restResult(T data, int code, String msg) + { + R r = new R<>(); + r.setCode(code); + r.setData(data); + r.setMsg(msg); + return r; + } + + public static Boolean isError(R ret) + { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) + { + return R.SUCCESS == ret.getCode(); + } + + public R() + { + } + + public int getCode() + { + return code; + } + + public void setCode(int code) + { + this.code = code; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public T getData() + { + return data; + } + + public void setData(T data) + { + this.data = data; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/TableData.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/TableData.java new file mode 100644 index 000000000..bbc9ffaeb --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/TableData.java @@ -0,0 +1,73 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * Page Response + */ + +public class TableData + implements Serializable +{ + @Serial + private static final long serialVersionUID = 1L; + + /** + * Total number of table data + */ + private long total; + + /** + * page data + */ + private List rows; + + public TableData(List list, long total) + { + this.rows = list; + this.total = total; + } + + public static TableData build(List list, long total) + { + return new TableData<>(list, total); + } + + public TableData() + {} + + public long getTotal() + { + return total; + } + + public void setTotal(long total) + { + this.total = total; + } + + public List getRows() + { + return rows; + } + + public void setRows(List rows) + { + this.rows = rows; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/GlobalPropertyRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/GlobalPropertyRequest.java new file mode 100644 index 000000000..60ec23582 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/GlobalPropertyRequest.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +import io.trino.gateway.ha.router.ResourceGroupsManager; + +/** + * Parameters for adding, modifying, and deleting GlobalProperty. + */ +public class GlobalPropertyRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + private ResourceGroupsManager.GlobalPropertiesDetail data; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public ResourceGroupsManager.GlobalPropertiesDetail getData() + { + return data; + } + + public void setData(ResourceGroupsManager.GlobalPropertiesDetail data) + { + this.data = data; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryDistributionRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryDistributionRequest.java new file mode 100644 index 000000000..c0716a1a8 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryDistributionRequest.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Query parameters for Distribution + */ +public class QueryDistributionRequest +{ + /** + * Latest statistics for multiple hours. + */ + private Integer latestHour = 1; + + public Integer getLatestHour() + { + return latestHour; + } + + public void setLatestHour(Integer latestHour) + { + this.latestHour = latestHour; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryGlobalPropertyRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryGlobalPropertyRequest.java new file mode 100644 index 000000000..968a3141f --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryGlobalPropertyRequest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Query parameters for GlobalProperty + */ +public class QueryGlobalPropertyRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + + /** + * Optional, you can query the configuration for a specific name. + */ + private String name; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryHistoryRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryHistoryRequest.java new file mode 100644 index 000000000..62cd0f244 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryHistoryRequest.java @@ -0,0 +1,96 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Query parameters for History + */ +public class QueryHistoryRequest +{ + /** + * page index + */ + private Integer page = 1; + + /** + * page size + */ + private Integer size = 10; + + /** + * Query histories of specified user. + * ADMIN role is optional, other roles are mandatory. + */ + private String user; + + /** + * Optional, you can query the history based on the backendUrl. + */ + private String backendUrl; + + /** + * Optional, you can query the query history based on the queryId of Trino. + */ + private String queryId; + + public Integer getPage() + { + return page; + } + + public void setPage(Integer page) + { + this.page = page; + } + + public Integer getSize() + { + return size; + } + + public void setSize(Integer size) + { + this.size = size; + } + + public String getUser() + { + return user; + } + + public void setUser(String user) + { + this.user = user; + } + + public String getBackendUrl() + { + return backendUrl; + } + + public void setBackendUrl(String backendUrl) + { + this.backendUrl = backendUrl; + } + + public String getQueryId() + { + return queryId; + } + + public void setQueryId(String queryId) + { + this.queryId = queryId; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryResourceGroupsRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryResourceGroupsRequest.java new file mode 100644 index 000000000..1832b95a2 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QueryResourceGroupsRequest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Query parameters for ResourceGroups + */ +public class QueryResourceGroupsRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + + /** + * Query a single item by id. + */ + private Long resourceGroupId; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public Long getResourceGroupId() + { + return resourceGroupId; + } + + public void setResourceGroupId(Long resourceGroupId) + { + this.resourceGroupId = resourceGroupId; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QuerySelectorsRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QuerySelectorsRequest.java new file mode 100644 index 000000000..87b88f63f --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/QuerySelectorsRequest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Query parameters for Selectors + */ +public class QuerySelectorsRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + + /** + * Query the selectors under the resource Group. + */ + private Long resourceGroupId; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public Long getResourceGroupId() + { + return resourceGroupId; + } + + public void setResourceGroupId(Long resourceGroupId) + { + this.resourceGroupId = resourceGroupId; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/ResourceGroupsRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/ResourceGroupsRequest.java new file mode 100644 index 000000000..52f1a8fd8 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/ResourceGroupsRequest.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +import io.trino.gateway.ha.router.ResourceGroupsManager; + +/** + * Parameters for adding, modifying, and deleting ResourceGroups. + */ +public class ResourceGroupsRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + private ResourceGroupsManager.ResourceGroupsDetail data; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public ResourceGroupsManager.ResourceGroupsDetail getData() + { + return data; + } + + public void setData(ResourceGroupsManager.ResourceGroupsDetail data) + { + this.data = data; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/RestLoginRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/RestLoginRequest.java new file mode 100644 index 000000000..fc1c14334 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/RestLoginRequest.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +/** + * Receiving form login parameters. + */ +public class RestLoginRequest +{ + private String username; + private String password; + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/SelectorsRequest.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/SelectorsRequest.java new file mode 100644 index 000000000..13fc0a1df --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/request/SelectorsRequest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.request; + +import io.trino.gateway.ha.router.ResourceGroupsManager; + +/** + * Parameters for adding, modifying, and deleting Selectors. + */ +public class SelectorsRequest +{ + /** + * Optional, defaults to the Schema of the configuration file. + */ + private String useSchema; + + /** + * This field is used for adding, modifying, and deleting. + */ + private ResourceGroupsManager.SelectorsDetail data; + + /** + * This field is only used for modification + */ + private ResourceGroupsManager.SelectorsDetail oldData; + + public String getUseSchema() + { + return useSchema; + } + + public void setUseSchema(String useSchema) + { + this.useSchema = useSchema; + } + + public ResourceGroupsManager.SelectorsDetail getData() + { + return data; + } + + public void setData(ResourceGroupsManager.SelectorsDetail data) + { + this.data = data; + } + + public ResourceGroupsManager.SelectorsDetail getOldData() + { + return oldData; + } + + public void setOldData(ResourceGroupsManager.SelectorsDetail oldData) + { + this.oldData = oldData; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/BackendResponse.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/BackendResponse.java new file mode 100644 index 000000000..1912bc09b --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/BackendResponse.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.response; + +import io.trino.gateway.ha.config.ProxyBackendConfiguration; + +/** + * Backend Request Body + */ +public class BackendResponse + extends ProxyBackendConfiguration +{ + private Integer queued; + private Integer running; + + public Integer getQueued() + { + return queued; + } + + public void setQueued(Integer queued) + { + this.queued = queued; + } + + public Integer getRunning() + { + return running; + } + + public void setRunning(Integer running) + { + this.running = running; + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/DistributionResponse.java b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/DistributionResponse.java new file mode 100644 index 000000000..c66c05a37 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/domain/response/DistributionResponse.java @@ -0,0 +1,233 @@ +/* + * 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. + */ +package io.trino.gateway.ha.domain.response; + +import java.util.List; +import java.util.Map; + +/** + * QueryHistory Request Body + */ +public class DistributionResponse +{ + private Integer totalBackendCount; + private Integer offlineBackendCount; + private Integer onlineBackendCount; + + /** + * Total number of queries. + * The QueryDistributionRequest's latestHour parameter will affect the statistical range. + */ + private Long totalQueryCount; + + /** + * Average number of queries per minute. + * The QueryDistributionRequest's latestHour parameter will affect the statistical range. + */ + private Double averageQueryCountMinute; + + /** + * Average number of queries per second. + * The QueryDistributionRequest's latestHour parameter will affect the statistical range. + */ + private Double averageQueryCountSecond; + + /** + * Pie chart of the number of backend queries. + * The QueryDistributionRequest's latestHour parameter will affect the statistical range. + */ + private List distributionChart; + + /** + * Line graph of the number of queries per minute for each backend. + * The QueryDistributionRequest's latestHour parameter will affect the statistical range. + */ + private Map> lineChart; + private String startTime; + + public String getStartTime() + { + return startTime; + } + + public void setStartTime(String startTime) + { + this.startTime = startTime; + } + + public Integer getTotalBackendCount() + { + return totalBackendCount; + } + + public void setTotalBackendCount(Integer totalBackendCount) + { + this.totalBackendCount = totalBackendCount; + } + + public Integer getOfflineBackendCount() + { + return offlineBackendCount; + } + + public void setOfflineBackendCount(Integer offlineBackendCount) + { + this.offlineBackendCount = offlineBackendCount; + } + + public Integer getOnlineBackendCount() + { + return onlineBackendCount; + } + + public void setOnlineBackendCount(Integer onlineBackendCount) + { + this.onlineBackendCount = onlineBackendCount; + } + + public Long getTotalQueryCount() + { + return totalQueryCount; + } + + public void setTotalQueryCount(Long totalQueryCount) + { + this.totalQueryCount = totalQueryCount; + } + + public Double getAverageQueryCountMinute() + { + return averageQueryCountMinute; + } + + public void setAverageQueryCountMinute(Double averageQueryCountMinute) + { + this.averageQueryCountMinute = averageQueryCountMinute; + } + + public Double getAverageQueryCountSecond() + { + return averageQueryCountSecond; + } + + public void setAverageQueryCountSecond(Double averageQueryCountSecond) + { + this.averageQueryCountSecond = averageQueryCountSecond; + } + + public List getDistributionChart() + { + return distributionChart; + } + + public void setDistributionChart(List distributionChart) + { + this.distributionChart = distributionChart; + } + + public Map> getLineChart() + { + return lineChart; + } + + public void setLineChart(Map> lineChart) + { + this.lineChart = lineChart; + } + + public static class DistributionChart + { + private String backendUrl; + private Long queryCount; + private String name; + + public String getBackendUrl() + { + return backendUrl; + } + + public void setBackendUrl(String backendUrl) + { + this.backendUrl = backendUrl; + } + + public Long getQueryCount() + { + return queryCount; + } + + public void setQueryCount(Long queryCount) + { + this.queryCount = queryCount; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + } + + public static class LineChart + { + private String minute; + private String backendUrl; + private Long queryCount; + private String name; + + public String getMinute() + { + return minute; + } + + public void setMinute(String minute) + { + this.minute = minute; + } + + public String getBackendUrl() + { + return backendUrl; + } + + public void setBackendUrl(String backendUrl) + { + this.backendUrl = backendUrl; + } + + public Long getQueryCount() + { + return queryCount; + } + + public void setQueryCount(Long queryCount) + { + this.queryCount = queryCount; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java b/gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java index 8f7edba34..2d9c38fc0 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java @@ -105,7 +105,8 @@ private LbOAuthManager getOAuthManager(HaGatewayConfiguration configuration) AuthenticationConfiguration authenticationConfiguration = configuration.getAuthentication(); if (authenticationConfiguration != null && authenticationConfiguration.getOauth() != null) { - return new LbOAuthManager(authenticationConfiguration.getOauth()); + return new LbOAuthManager(authenticationConfiguration.getOauth(), + configuration.getPagePermissions()); } return null; } @@ -116,7 +117,8 @@ private LbFormAuthManager getFormAuthManager(HaGatewayConfiguration configuratio if (authenticationConfiguration != null && authenticationConfiguration.getForm() != null) { return new LbFormAuthManager(authenticationConfiguration.getForm(), - configuration.getPresetUsers()); + configuration.getPresetUsers(), + configuration.getPagePermissions()); } return null; } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/persistence/dao/QueryHistoryDao.java b/gateway-ha/src/main/java/io/trino/gateway/ha/persistence/dao/QueryHistoryDao.java index b2bdbe7d6..b23fcc814 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/persistence/dao/QueryHistoryDao.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/persistence/dao/QueryHistoryDao.java @@ -13,10 +13,15 @@ */ package io.trino.gateway.ha.persistence.dao; +import org.jdbi.v3.core.mapper.MapMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.Define; import org.jdbi.v3.sqlobject.statement.SqlQuery; import org.jdbi.v3.sqlobject.statement.SqlUpdate; +import org.jdbi.v3.sqlobject.statement.UseRowMapper; import java.util.List; +import java.util.Map; public interface QueryHistoryDao { @@ -41,6 +46,31 @@ public interface QueryHistoryDao """) String findBackendUrlByQueryId(String queryId); + @SqlQuery(""" + SELECT * FROM query_history + WHERE 1 = 1 + ORDER BY created DESC + LIMIT :limit + OFFSET :offset + """) + List pageQueryHistory(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset); + + @SqlQuery(""" + SELECT count(1) FROM query_history + """) + Long count(); + + @SqlQuery(""" + SELECT CONCAT(FLOOR(created / 1000 / 60)) AS minute, + backend_url AS backend_url, + COUNT(1) AS query_count + FROM query_history + WHERE created > :created + GROUP BY minute, backend_url + """) + @UseRowMapper(MapMapper.class) + List> findDistribution(long created); + @SqlUpdate(""" INSERT INTO query_history (query_id, query_text, backend_url, user_name, source, created) VALUES (:queryId, :queryText, :backendUrl, :userName, :source, :created) diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/EntityEditorResource.java b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/EntityEditorResource.java index 50970e78c..6065ca190 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/EntityEditorResource.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/EntityEditorResource.java @@ -17,7 +17,6 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.inject.Inject; -import io.dropwizard.views.common.View; import io.trino.gateway.ha.config.ProxyBackendConfiguration; import io.trino.gateway.ha.router.GatewayBackendManager; import io.trino.gateway.ha.router.ResourceGroupsManager; @@ -31,20 +30,15 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; -import java.util.Objects; -import static com.google.common.base.MoreObjects.toStringHelper; import static io.trino.gateway.ha.router.ResourceGroupsManager.ResourceGroupsDetail; import static io.trino.gateway.ha.router.ResourceGroupsManager.SelectorsDetail; import static java.util.Objects.requireNonNull; @@ -68,13 +62,6 @@ public EntityEditorResource(GatewayBackendManager gatewayBackendManager, Resourc this.routingManager = requireNonNull(routingManager, "routingManager is null"); } - @GET - @Produces(MediaType.TEXT_HTML) - public EntityView entityUi(@Context SecurityContext securityContext) - { - return new EntityView("/template/entity-view.ftl", securityContext); - } - @GET @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @@ -151,53 +138,4 @@ public Response getAllEntitiesForType( } return Response.ok(ImmutableList.of()).build(); } - - public static class EntityView - extends View - { - private String displayName; - - protected EntityView(String templateName, SecurityContext securityContext) - { - super(templateName, Charset.defaultCharset()); - setDisplayName(securityContext.getUserPrincipal().getName()); - } - - public String getDisplayName() - { - return this.displayName; - } - - public void setDisplayName(String displayName) - { - this.displayName = displayName; - } - - @Override - public boolean equals(Object o) - { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EntityView that = (EntityView) o; - return Objects.equals(displayName, that.displayName); - } - - @Override - public int hashCode() - { - return Objects.hash(displayName); - } - - @Override - public String toString() - { - return toStringHelper(this) - .add("displayName", displayName) - .toString(); - } - } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayViewResource.java b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayViewResource.java index 90294520e..1cac430e4 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayViewResource.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayViewResource.java @@ -14,9 +14,7 @@ package io.trino.gateway.ha.resource; import com.google.inject.Inject; -import io.dropwizard.views.common.View; import io.trino.gateway.ha.config.ProxyBackendConfiguration; -import io.trino.gateway.ha.router.BackendStateManager; import io.trino.gateway.ha.router.GatewayBackendManager; import io.trino.gateway.ha.router.QueryHistoryManager; import io.trino.gateway.ha.security.LbPrincipal; @@ -26,35 +24,27 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.SecurityContext; -import java.nio.charset.Charset; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; -import static com.google.common.base.MoreObjects.toStringHelper; import static java.util.Objects.requireNonNull; -@RolesAllowed("USER") @Path("/") public class GatewayViewResource { - private static final long START_TIME = System.currentTimeMillis(); - private final GatewayBackendManager gatewayBackendManager; private final QueryHistoryManager queryHistoryManager; - private final BackendStateManager backendStateManager; @Inject - public GatewayViewResource(GatewayBackendManager gatewayBackendManager, QueryHistoryManager queryHistoryManager, BackendStateManager backendStateManager) + public GatewayViewResource(GatewayBackendManager gatewayBackendManager, QueryHistoryManager queryHistoryManager) { this.gatewayBackendManager = requireNonNull(gatewayBackendManager, "gatewayBackendManager is null"); this.queryHistoryManager = requireNonNull(queryHistoryManager, "queryHistoryManager is null"); - this.backendStateManager = requireNonNull(backendStateManager, "backendStateManager is null"); } private Optional getUserNameForQueryHistory(SecurityContext securityContext) @@ -70,47 +60,13 @@ private Optional getUserNameForQueryHistory(SecurityContext securityCont @GET @Produces(MediaType.TEXT_HTML) - public GatewayView getQueryDetailsView(@Context SecurityContext securityContext) - { - GatewayView queryHistoryView = new GatewayView("/template/query-history-view.ftl", - securityContext); - - // Get all active backends - queryHistoryView.setBackendConfigurations( - gatewayBackendManager.getAllBackends()); - - Optional userName = getUserNameForQueryHistory(securityContext); - queryHistoryView.setQueryHistory(queryHistoryManager.fetchQueryHistory(userName)); - queryHistoryView.setQueryDistribution(getQueryHistoryDistribution(securityContext)); - return queryHistoryView; - } - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("viewgateway") - public GatewayView getGatewayView(@Context SecurityContext securityContext) + public Response getIndex() { - GatewayView gatewayView = new GatewayView("/template/gateway-view.ftl", - securityContext); - // Get all Backends - gatewayView.setBackendConfigurations( - gatewayBackendManager.getAllBackends()); - - Map backendStates = gatewayBackendManager - .getAllBackends() - .stream() - .map(backendStateManager::getBackendState) - .collect(Collectors.toMap(s -> s.name(), s -> s)); - - gatewayView.setBackendStates(backendStates); - - Optional userName = getUserNameForQueryHistory(securityContext); - gatewayView.setQueryHistory(queryHistoryManager.fetchQueryHistory(userName)); - gatewayView.setQueryDistribution(getQueryHistoryDistribution(securityContext)); - return gatewayView; + return Response.ok(getClass().getResourceAsStream("/static/index.html")).build(); } @GET + @RolesAllowed("USER") @Path("api/queryHistory") @Produces(MediaType.APPLICATION_JSON) public List getQueryHistory(@Context SecurityContext @@ -121,6 +77,7 @@ public List getQueryHistory(@Context SecurityCo } @GET + @RolesAllowed("USER") @Path("api/activeBackends") @Produces(MediaType.APPLICATION_JSON) public List getActiveBackends() @@ -129,6 +86,7 @@ public List getActiveBackends() } @GET + @RolesAllowed("USER") @Path("api/queryHistoryDistribution") @Produces(MediaType.APPLICATION_JSON) public Map getQueryHistoryDistribution(@Context SecurityContext @@ -159,113 +117,4 @@ public Map getQueryHistoryDistribution(@Context SecurityContext }); return clusterToQueryCount; } - - public static class GatewayView - extends View - { - private final long gatewayStartTime = START_TIME; - private String displayName; - private List backendConfigurations; - private List queryHistory; - private Map backendStates; - private Map queryDistribution; - - protected GatewayView(String templateName, SecurityContext securityContext) - { - super(templateName, Charset.defaultCharset()); - setDisplayName(securityContext.getUserPrincipal().getName()); - } - - public long getGatewayStartTime() - { - return this.gatewayStartTime; - } - - public String getDisplayName() - { - return this.displayName; - } - - public void setDisplayName(String displayName) - { - this.displayName = displayName; - } - - public List getBackendConfigurations() - { - return this.backendConfigurations; - } - - public void setBackendConfigurations(List backendConfigurations) - { - this.backendConfigurations = backendConfigurations; - } - - public List getQueryHistory() - { - return this.queryHistory; - } - - public void setQueryHistory(List queryHistory) - { - this.queryHistory = queryHistory; - } - - public Map getBackendStates() - { - return this.backendStates; - } - - public void setBackendStates(Map backendStates) - { - this.backendStates = backendStates; - } - - public Map getQueryDistribution() - { - return this.queryDistribution; - } - - public void setQueryDistribution(Map queryDistribution) - { - this.queryDistribution = queryDistribution; - } - - @Override - public boolean equals(Object o) - { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - GatewayView that = (GatewayView) o; - return gatewayStartTime == that.gatewayStartTime && - Objects.equals(displayName, that.displayName) && - Objects.equals(backendConfigurations, that.backendConfigurations) && - Objects.equals(queryHistory, that.queryHistory) && - Objects.equals(backendStates, that.backendStates) && - Objects.equals(queryDistribution, that.queryDistribution); - } - - @Override - public int hashCode() - { - return Objects.hash(gatewayStartTime, displayName, backendConfigurations, queryHistory, backendStates, queryDistribution); - } - - @Override - public String toString() - { - return toStringHelper(this) - .add("gatewayStartTime", gatewayStartTime) - .add("displayName", displayName) - .add("backendConfigurations", backendConfigurations) - .add("queryHistory", queryHistory) - .add("backendStates", backendStates) - .add("queryDistribution", queryDistribution) - .toString(); - } - } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java new file mode 100644 index 000000000..e8c316558 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java @@ -0,0 +1,415 @@ +/* + * 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. + */ +package io.trino.gateway.ha.resource; + +import com.google.common.base.Strings; +import com.google.inject.Inject; +import io.trino.gateway.ha.config.ProxyBackendConfiguration; +import io.trino.gateway.ha.domain.R; +import io.trino.gateway.ha.domain.TableData; +import io.trino.gateway.ha.domain.request.GlobalPropertyRequest; +import io.trino.gateway.ha.domain.request.QueryDistributionRequest; +import io.trino.gateway.ha.domain.request.QueryGlobalPropertyRequest; +import io.trino.gateway.ha.domain.request.QueryHistoryRequest; +import io.trino.gateway.ha.domain.request.QueryResourceGroupsRequest; +import io.trino.gateway.ha.domain.request.QuerySelectorsRequest; +import io.trino.gateway.ha.domain.request.ResourceGroupsRequest; +import io.trino.gateway.ha.domain.request.SelectorsRequest; +import io.trino.gateway.ha.domain.response.BackendResponse; +import io.trino.gateway.ha.domain.response.DistributionResponse; +import io.trino.gateway.ha.router.BackendStateManager; +import io.trino.gateway.ha.router.GatewayBackendManager; +import io.trino.gateway.ha.router.HaGatewayManager; +import io.trino.gateway.ha.router.QueryHistoryManager; +import io.trino.gateway.ha.router.ResourceGroupsManager; +import io.trino.gateway.ha.security.LbPrincipal; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import org.apache.commons.lang3.ObjectUtils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; + +@Path("/webapp") +public class GatewayWebAppResource +{ + private static final LocalDateTime START_TIME = LocalDateTime.now(); + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private final GatewayBackendManager gatewayBackendManager; + private final QueryHistoryManager queryHistoryManager; + private final BackendStateManager backendStateManager; + private final ResourceGroupsManager resourceGroupsManager; + + @Inject + public GatewayWebAppResource(GatewayBackendManager gatewayBackendManager, QueryHistoryManager queryHistoryManager, + BackendStateManager backendStateManager, ResourceGroupsManager resourceGroupsManager) + { + this.gatewayBackendManager = requireNonNull(gatewayBackendManager, "gatewayBackendManager is null"); + this.queryHistoryManager = requireNonNull(queryHistoryManager, "queryHistoryManager is null"); + this.backendStateManager = requireNonNull(backendStateManager, "backendStateManager is null"); + this.resourceGroupsManager = requireNonNull(resourceGroupsManager, "resourceGroupsManager is null"); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/getAllBackends") + public Response getAllBackends() + { + List allBackends = gatewayBackendManager.getAllBackends(); + List data = allBackends.stream().map(b -> { + BackendStateManager.BackendState backendState = backendStateManager.getBackendState(b); + Map state = backendState.state(); + BackendResponse backendResponse = new BackendResponse(); + backendResponse.setQueued(state.get("QUEUED")); + backendResponse.setRunning(state.get("RUNNING")); + backendResponse.setName(b.getName()); + backendResponse.setProxyTo(b.getProxyTo()); + backendResponse.setActive(b.isActive()); + backendResponse.setRoutingGroup(b.getRoutingGroup()); + backendResponse.setExternalUrl(b.getExternalUrl()); + return backendResponse; + }).toList(); + return Response.ok(R.ok(data)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/findQueryHistory") + public Response findQueryHistory(QueryHistoryRequest query, + @Context SecurityContext securityContext) + { + LbPrincipal principal = (LbPrincipal) securityContext.getUserPrincipal(); + String[] roles = principal.getMemberOf().orElse("").split("_"); + if (!Arrays.asList(roles).contains("ADMIN")) { + query.setUser(principal.getName()); + } + TableData queryHistory = queryHistoryManager.findQueryHistory(query); + return Response.ok(R.ok(queryHistory)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/getDistribution") + public Response getDistribution(QueryDistributionRequest query) + { + List allBackends = gatewayBackendManager + .getAllBackends(); + Map urlToNameMap = allBackends + .stream().collect(Collectors.toMap(ProxyBackendConfiguration::getProxyTo, ProxyBackendConfiguration::getName, (o, n) -> n)); + Map> activeMap = allBackends.stream().collect(Collectors.groupingBy(ProxyBackendConfiguration::isActive)); + Integer latestHour = query.getLatestHour(); + Long ts = System.currentTimeMillis() - (latestHour * 60 * 60 * 1000); + List lineChart = queryHistoryManager.findDistribution(ts); + lineChart.forEach(qh -> qh.setName(urlToNameMap.get(qh.getBackendUrl()))); + Map> lineChartMap = lineChart.stream().collect(Collectors.groupingBy(DistributionResponse.LineChart::getName)); + List distributionChart = lineChartMap.values().stream().map(d -> { + DistributionResponse.DistributionChart dc = new DistributionResponse.DistributionChart(); + DistributionResponse.LineChart lc = d.get(0); + long sum = d.stream().collect(Collectors.summarizingLong(DistributionResponse.LineChart::getQueryCount)).getSum(); + dc.setQueryCount(sum); + dc.setBackendUrl(lc.getBackendUrl()); + dc.setName(lc.getName()); + return dc; + }).collect(Collectors.toList()); + long totalQueryCount = distributionChart.stream().collect(Collectors.summarizingLong(DistributionResponse.DistributionChart::getQueryCount)).getSum(); + DistributionResponse distributionResponse = new DistributionResponse(); + distributionResponse.setTotalBackendCount(allBackends.size()); + distributionResponse.setOfflineBackendCount(ObjectUtils.defaultIfNull(activeMap.get(false), Collections.emptyList()).size()); + distributionResponse.setOnlineBackendCount(ObjectUtils.defaultIfNull(activeMap.get(true), Collections.emptyList()).size()); + distributionResponse.setLineChart(lineChartMap); + distributionResponse.setDistributionChart(distributionChart); + distributionResponse.setTotalQueryCount(totalQueryCount); + distributionResponse.setAverageQueryCountSecond(totalQueryCount / (latestHour * 60d * 60d)); + distributionResponse.setAverageQueryCountMinute(totalQueryCount / (latestHour * 60d)); + distributionResponse.setStartTime(START_TIME.format(formatter)); + return Response.ok(R.ok(distributionResponse)).build(); + } + + @POST + @RolesAllowed("ADMIN") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/saveBackend") + public Response saveBackend(ProxyBackendConfiguration backend) + { + ProxyBackendConfiguration proxyBackendConfiguration = gatewayBackendManager.addBackend(backend); + return Response.ok(R.ok(proxyBackendConfiguration)).build(); + } + + @POST + @RolesAllowed("ADMIN") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/updateBackend") + public Response updateBackend(ProxyBackendConfiguration backend) + { + ProxyBackendConfiguration proxyBackendConfiguration = gatewayBackendManager.updateBackend(backend); + return Response.ok(R.ok(proxyBackendConfiguration)).build(); + } + + @POST + @RolesAllowed("ADMIN") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/deleteBackend") + public Response deleteBackend(ProxyBackendConfiguration backend) + { + ((HaGatewayManager) gatewayBackendManager).deleteBackend(backend.getName()); + return Response.ok(R.ok(true)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/saveResourceGroup") + public Response saveResourceGroup(ResourceGroupsRequest request) + { + ResourceGroupsManager.ResourceGroupsDetail newResourceGroup = + resourceGroupsManager.createResourceGroup(request.getData(), request.getUseSchema()); + return Response.ok(R.ok(newResourceGroup)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/updateResourceGroup") + public Response updateResourceGroup(ResourceGroupsRequest request) + { + ResourceGroupsManager.ResourceGroupsDetail newResourceGroup = + resourceGroupsManager.updateResourceGroup(request.getData(), request.getUseSchema()); + return Response.ok(R.ok(newResourceGroup)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/deleteResourceGroup") + public Response deleteResourceGroup(ResourceGroupsRequest request) + { + ResourceGroupsManager.ResourceGroupsDetail resourceGroupsDetail = request.getData(); + resourceGroupsManager.deleteResourceGroup(resourceGroupsDetail.getResourceGroupId(), request.getUseSchema()); + return Response.ok(R.ok(true)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/findResourceGroup") + public Response findResourceGroup(QueryResourceGroupsRequest request) + { + List resourceGroupsDetailList = resourceGroupsManager.readAllResourceGroups(request.getUseSchema()); + return Response.ok(R.ok(resourceGroupsDetailList)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/getResourceGroup") + public Response readResourceGroup(QueryResourceGroupsRequest request) + { + if (Objects.isNull(request.getResourceGroupId())) { + return Response.ok(R.fail("ResourceGroupId cannot be null!")).build(); + } + List resourceGroup = resourceGroupsManager.readResourceGroup( + request.getResourceGroupId(), + request.getUseSchema()); + return Response.ok(R.ok(resourceGroup.stream().findFirst())).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/saveSelector") + public Response saveSelector(SelectorsRequest selectorsRequest) + { + ResourceGroupsManager.SelectorsDetail updatedSelector = this.resourceGroupsManager.createSelector( + selectorsRequest.getData(), + selectorsRequest.getUseSchema()); + return Response.ok(R.ok(updatedSelector)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/updateSelector") + public Response updateSelector(SelectorsRequest selectorsRequest) + { + ResourceGroupsManager.SelectorsDetail updatedSelector = resourceGroupsManager.updateSelector( + selectorsRequest.getOldData(), + selectorsRequest.getData(), + selectorsRequest.getUseSchema()); + return Response.ok(R.ok(updatedSelector)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/deleteSelector") + public Response deleteSelector(SelectorsRequest request) + { + resourceGroupsManager.deleteSelector(request.getData(), request.getUseSchema()); + return Response.ok(R.ok(true)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/findSelector") + public Response findSelector(QuerySelectorsRequest request) + { + List selectorsDetailList = resourceGroupsManager.readAllSelectors( + request.getUseSchema()); + return Response.ok(R.ok(selectorsDetailList)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/getSelector") + public Response getSelector(QuerySelectorsRequest request) + { + if (Objects.isNull(request.getResourceGroupId())) { + return Response.ok(R.fail("ResourceGroupId cannot be null!")).build(); + } + List selectors = resourceGroupsManager.readSelector( + request.getResourceGroupId(), + request.getUseSchema()); + return Response.ok(R.ok(selectors.stream().findFirst())).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/saveGlobalProperty") + public Response saveGlobalProperty(GlobalPropertyRequest request) + { + ResourceGroupsManager.GlobalPropertiesDetail globalProperty = resourceGroupsManager.createGlobalProperty( + request.getData(), + request.getUseSchema()); + return Response.ok(R.ok(globalProperty)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/updateGlobalProperty") + public Response updateGlobalProperty(GlobalPropertyRequest request) + { + ResourceGroupsManager.GlobalPropertiesDetail globalProperty = resourceGroupsManager.updateGlobalProperty( + request.getData(), + request.getUseSchema()); + return Response.ok(R.ok(globalProperty)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/deleteGlobalProperty") + public Response deleteGlobalProperty(GlobalPropertyRequest request) + { + ResourceGroupsManager.GlobalPropertiesDetail globalPropertiesDetail = request.getData(); + resourceGroupsManager.deleteGlobalProperty( + globalPropertiesDetail.getName(), + request.getUseSchema()); + return Response.ok(R.ok(true)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/findGlobalProperty") + public Response readAllGlobalProperties(QueryGlobalPropertyRequest request) + { + List globalPropertiesDetailList; + if (Strings.isNullOrEmpty(request.getName())) { + globalPropertiesDetailList = resourceGroupsManager.readAllGlobalProperties(request.getUseSchema()); + } + else { + globalPropertiesDetailList = resourceGroupsManager.readGlobalProperty(request.getName(), request.getUseSchema()); + } + return Response.ok(R.ok(globalPropertiesDetailList)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/getGlobalProperty") + public Response readGlobalProperty(QueryGlobalPropertyRequest request) + { + if (Strings.isNullOrEmpty(request.getName())) { + return Response.ok(R.fail("Name cannot be null!")).build(); + } + List globalProperty = resourceGroupsManager.readGlobalProperty(request.getName(), request.getUseSchema()); + return Response.ok(R.ok(globalProperty.stream().findFirst())).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/saveExactMatchSourceSelector") + public Response saveExactMatchSourceSelector( + ResourceGroupsManager.ExactSelectorsDetail exactMatchSourceSelector) + { + ResourceGroupsManager.ExactSelectorsDetail newExactMatchSourceSelector = resourceGroupsManager.createExactMatchSourceSelector(exactMatchSourceSelector); + return Response.ok(R.ok(newExactMatchSourceSelector)).build(); + } + + @POST + @RolesAllowed("USER") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/findExactMatchSourceSelector") + public Response readExactMatchSourceSelector() + { + List selectorsDetailList = resourceGroupsManager.readExactMatchSourceSelector(); + return Response.ok(R.ok(selectorsDetailList)).build(); + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/LoginResource.java b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/LoginResource.java index 12259b2cb..1178848b0 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/resource/LoginResource.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/resource/LoginResource.java @@ -14,22 +14,28 @@ package io.trino.gateway.ha.resource; import com.google.inject.Inject; -import io.dropwizard.views.common.View; +import io.trino.gateway.ha.domain.R; +import io.trino.gateway.ha.domain.request.RestLoginRequest; import io.trino.gateway.ha.security.LbFormAuthManager; import io.trino.gateway.ha.security.LbOAuthManager; -import io.trino.gateway.ha.security.SessionCookie; +import io.trino.gateway.ha.security.LbPrincipal; import jakarta.annotation.Nullable; -import jakarta.ws.rs.FormParam; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; -import java.nio.charset.Charset; +import java.util.Collections; +import java.util.List; +import java.util.Map; @Path("/") @Produces(MediaType.APPLICATION_JSON) @@ -45,14 +51,17 @@ public LoginResource(@Nullable LbOAuthManager oauthManager, @Nullable LbFormAuth this.formAuthManager = formAuthManager; } + @POST @Path("sso") - @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) public Response login() { if (oauthManager == null) { throw new WebApplicationException("OAuth configuration is not setup"); } - return oauthManager.getAuthorizationCode(); + String authorizationUrl = oauthManager.getAuthorizationCode(); + return Response.ok(R.ok("Ok", authorizationUrl)).build(); } @Path("oidc/callback") @@ -66,42 +75,73 @@ public Response callback(@QueryParam("code") String code) } @POST - @Path("login_form") - public Response processLoginForm( - @FormParam("username") String userName, - @FormParam("password") String password) + @Path("login") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response processRESTLogin(RestLoginRequest loginForm) { if (formAuthManager == null) { + if (oauthManager == null) { + return Response.ok(R.ok(Map.of("token", loginForm.getUsername()))).build(); + } throw new WebApplicationException("Form authentication is not setup"); } - return formAuthManager.processLoginForm(userName, password); + R r = formAuthManager.processRESTLogin(loginForm); + return Response.ok(r).build(); } - @GET - @Path("login") - @Produces(MediaType.TEXT_HTML) - public LoginResource.LoginForm loginFormUi() + @POST + @Path("logout") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response processRESTLogin() { - if (formAuthManager == null) { - throw new WebApplicationException("Form authentication is not setup"); - } - - return new LoginResource.LoginForm("/template/login-form.ftl"); + return Response.ok(R.ok()).build(); } - @Path("logout") - @GET - public Response logOut() + @POST + @RolesAllowed("USER") + @Path("userinfo") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response restUserinfo(@Context SecurityContext securityContext) { - return SessionCookie.logOut(); + LbPrincipal principal = (LbPrincipal) securityContext.getUserPrincipal(); + List roles = List.of(principal.getMemberOf().orElse("").split("_")); + List pagePermissions; + if (formAuthManager != null) { + pagePermissions = formAuthManager.processPagePermissions(roles); + } + else if (oauthManager != null) { + pagePermissions = oauthManager.processPagePermissions(roles); + } + else { + pagePermissions = Collections.emptyList(); + } + Map resMap = Map.of( + "roles", roles, + "permissions", pagePermissions, + "userId", principal.getName(), + "userName", principal.getName()); + return Response.ok(R.ok(resMap)).build(); } - public static class LoginForm - extends View + @POST + @Path("loginType") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response loginType() { - protected LoginForm(String templateName) - { - super(templateName, Charset.defaultCharset()); + String loginType; + if (formAuthManager != null) { + loginType = "form"; + } + else if (oauthManager != null) { + loginType = "oauth"; + } + else { + loginType = "none"; } + return Response.ok(R.ok("Ok", loginType)).build(); } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/router/HaQueryHistoryManager.java b/gateway-ha/src/main/java/io/trino/gateway/ha/router/HaQueryHistoryManager.java index 82f5760da..4a6f863f3 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/router/HaQueryHistoryManager.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/router/HaQueryHistoryManager.java @@ -13,12 +13,22 @@ */ package io.trino.gateway.ha.router; +import io.trino.gateway.ha.domain.TableData; +import io.trino.gateway.ha.domain.request.QueryHistoryRequest; +import io.trino.gateway.ha.domain.response.DistributionResponse; import io.trino.gateway.ha.persistence.dao.QueryHistory; import io.trino.gateway.ha.persistence.dao.QueryHistoryDao; +import io.trino.gateway.ha.util.PageUtil; +import org.apache.commons.lang3.StringUtils; import org.jdbi.v3.core.Jdbi; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import static java.util.Objects.requireNonNull; @@ -84,4 +94,43 @@ public String getBackendForQueryId(String queryId) { return dao.findBackendUrlByQueryId(queryId); } + + @Override + public TableData findQueryHistory(QueryHistoryRequest query) + { + int start = PageUtil.getStart(query.getPage(), query.getSize()); + String condition = ""; + if (StringUtils.isNotBlank(query.getUser())) { + condition += " and user_name = '" + query.getUser() + "'"; + } + if (StringUtils.isNotBlank(query.getBackendUrl())) { + condition += " and backend_url = '" + query.getBackendUrl() + "'"; + } + if (StringUtils.isNotBlank(query.getQueryId())) { + condition += " and query_id = '" + query.getQueryId() + "'"; + } + List histories = dao.pageQueryHistory(condition, query.getSize(), start); + List rows = upcast(histories); + Long total = dao.count(); + return TableData.build(rows, total); + } + + @Override + public List findDistribution(Long ts) + { + List> results = dao.findDistribution(ts); + List resList = new ArrayList<>(); + for (Map model : results) { + DistributionResponse.LineChart lineChart = new DistributionResponse.LineChart(); + long minute = Long.parseLong(model.get("minute").toString()); + Instant instant = Instant.ofEpochSecond(minute * 60L); + LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + lineChart.setMinute(dateTime.format(formatter)); + lineChart.setQueryCount(Long.parseLong(model.get("query_count").toString())); + lineChart.setBackendUrl(model.get("backend_url").toString()); + resList.add(lineChart); + } + return resList; + } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/router/QueryHistoryManager.java b/gateway-ha/src/main/java/io/trino/gateway/ha/router/QueryHistoryManager.java index 67317128e..d3a83a838 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/router/QueryHistoryManager.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/router/QueryHistoryManager.java @@ -13,6 +13,10 @@ */ package io.trino.gateway.ha.router; +import io.trino.gateway.ha.domain.TableData; +import io.trino.gateway.ha.domain.request.QueryHistoryRequest; +import io.trino.gateway.ha.domain.response.DistributionResponse; + import java.util.List; import java.util.Objects; import java.util.Optional; @@ -27,6 +31,10 @@ public interface QueryHistoryManager String getBackendForQueryId(String queryId); + TableData findQueryHistory(QueryHistoryRequest query); + + List findDistribution(Long ts); + class QueryDetail implements Comparable { diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/security/AuthorizedExceptionMapper.java b/gateway-ha/src/main/java/io/trino/gateway/ha/security/AuthorizedExceptionMapper.java new file mode 100644 index 000000000..4bd6152a8 --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/security/AuthorizedExceptionMapper.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package io.trino.gateway.ha.security; + +import io.trino.gateway.ha.domain.R; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; +import org.glassfish.jersey.server.internal.LocalizationMessages; + +@Provider +public class AuthorizedExceptionMapper + implements ExceptionMapper +{ + @Override + public Response toResponse(ForbiddenException exception) + { + if (exception.getMessage().equals(LocalizationMessages.USER_NOT_AUTHORIZED())) { + return Response.ok(R.fail(Response.Status.UNAUTHORIZED)).build(); + } + return exception.getResponse(); + } +} diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbFormAuthManager.java b/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbFormAuthManager.java index 0c97ccb0e..84dbdda90 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbFormAuthManager.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbFormAuthManager.java @@ -22,13 +22,16 @@ import io.trino.gateway.ha.config.FormAuthConfiguration; import io.trino.gateway.ha.config.LdapConfiguration; import io.trino.gateway.ha.config.UserConfiguration; -import jakarta.ws.rs.core.Response; +import io.trino.gateway.ha.domain.R; +import io.trino.gateway.ha.domain.request.RestLoginRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; public class LbFormAuthManager { @@ -38,12 +41,15 @@ public class LbFormAuthManager */ private final LbKeyProvider lbKeyProvider; Map presetUsers; + Map pagePermissions; private final LbLdapClient lbLdapClient; public LbFormAuthManager(FormAuthConfiguration configuration, - Map presetUsers) + Map presetUsers, + Map pagePermissions) { this.presetUsers = presetUsers; + this.pagePermissions = pagePermissions; if (configuration != null) { this.lbKeyProvider = new LbKeyProvider(configuration @@ -66,17 +72,19 @@ public String getUserIdField() return "sub"; } - public Response processLoginForm(String username, String password) + /** + * Login REST API + * + * @param loginForm {@link RestLoginRequest} + * @return token + */ + public R processRESTLogin(RestLoginRequest loginForm) { - if (authenticate(new BasicCredentials(username, password))) { - String token = getSelfSignedToken(username); - return Response.status(302).location(URI.create("/")) - .cookie(SessionCookie.getTokenCookie(token)) - .build(); + if (authenticate(new BasicCredentials(loginForm.getUsername(), loginForm.getPassword()))) { + String token = getSelfSignedToken(loginForm.getUsername()); + return R.ok(Map.of("token", token)); } - - return Response.status(302).location(URI.create("/")) - .build(); + return R.fail("Authentication failed."); } /** @@ -143,4 +151,17 @@ public boolean authenticate(BasicCredentials credentials) return false; } + + public List processPagePermissions(List roles) + { + for (String role : roles) { + String value = pagePermissions.get(role); + if (value == null) { + return Collections.emptyList(); + } + } + return roles.stream() + .flatMap(role -> Stream.of(pagePermissions.get(role).split("_"))) + .distinct().toList(); + } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbOAuthManager.java b/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbOAuthManager.java index ca7375e31..c3694183c 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbOAuthManager.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/security/LbOAuthManager.java @@ -34,9 +34,12 @@ import java.net.URI; import java.net.URL; import java.security.interfaces.RSAPublicKey; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; import static java.lang.String.format; @@ -47,10 +50,12 @@ public class LbOAuthManager * Cookie key to pass the token. */ private final OAuthConfiguration oauthConfig; + private final Map pagePermissions; - public LbOAuthManager(OAuthConfiguration configuration) + public LbOAuthManager(OAuthConfiguration configuration, Map pagePermissions) { this.oauthConfig = configuration; + this.pagePermissions = pagePermissions; } public String getUserIdField() @@ -72,6 +77,7 @@ public Response exchangeCodeForToken(String code, String redirectLocation) String clientId = oauthConfig.getClientId(); String clientSecret = oauthConfig.getClientSecret(); String redirectUri = oauthConfig.getRedirectUrl(); + String redirectWebUrl = oauthConfig.getRedirectWebUrl(); Client oauthClient = ClientBuilder.newBuilder().build(); Form form = new Form().param("grant_type", "authorization_code") @@ -94,7 +100,7 @@ public Response exchangeCodeForToken(String code, String redirectLocation) OidcTokens tokens = tokenResponse.readEntity(OidcTokens.class); return Response.status(302) - .location(URI.create(redirectLocation)) + .location(URI.create(redirectWebUrl == null ? redirectLocation : redirectWebUrl)) .cookie(SessionCookie.getTokenCookie(tokens.getIdToken())) .build(); } @@ -104,19 +110,15 @@ public Response exchangeCodeForToken(String code, String redirectLocation) * * @return redirect response to the authorization provider */ - public Response getAuthorizationCode() + public String getAuthorizationCode() { String authorizationEndpoint = oauthConfig.getAuthorizationEndpoint(); String clientId = oauthConfig.getClientId(); String redirectUrl = oauthConfig.getRedirectUrl(); String scopes = String.join("+", oauthConfig.getScopes()); - String url = format( + return format( "%s?client_id=%s&response_type=code&redirect_uri=%s&scope=%s", authorizationEndpoint, clientId, redirectUrl, scopes); - - return Response.status(302) - .location(URI.create(url)) - .build(); } /** @@ -148,6 +150,19 @@ public Optional> getClaimsFromIdToken(String idToken) return Optional.empty(); } + public List processPagePermissions(List roles) + { + for (String role : roles) { + String value = pagePermissions.get(role); + if (value == null) { + return Collections.emptyList(); + } + } + return roles.stream() + .flatMap(role -> Stream.of(pagePermissions.get(role).split("_"))) + .distinct().toList(); + } + @JsonIgnoreProperties(ignoreUnknown = true) static final class OidcTokens { diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/security/NoopAuthenticator.java b/gateway-ha/src/main/java/io/trino/gateway/ha/security/NoopAuthenticator.java index 359b5337d..74dc5b840 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/security/NoopAuthenticator.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/security/NoopAuthenticator.java @@ -26,6 +26,7 @@ public class NoopAuthenticator public Optional authenticate(String credentials) throws AuthenticationException { - return Optional.of(new LbPrincipal("user", Optional.empty())); + // If authentication is not configured, the default is 'ADMIN_USER_API'. + return Optional.of(new LbPrincipal("user", Optional.of("ADMIN_USER_API"))); } } diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/util/PageUtil.java b/gateway-ha/src/main/java/io/trino/gateway/ha/util/PageUtil.java new file mode 100644 index 000000000..9cf90ca5d --- /dev/null +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/util/PageUtil.java @@ -0,0 +1,36 @@ +/* + * 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. + */ +package io.trino.gateway.ha.util; + +/** + * Page Util + */ +public class PageUtil +{ + private static final int firstPageNo = 1; + + private PageUtil() + {} + + public static int getStart(int pageNo, int pageSize) + { + if (pageNo < firstPageNo) { + pageNo = firstPageNo; + } + if (pageSize < 1) { + pageSize = 0; + } + return (pageNo - firstPageNo) * pageSize; + } +} diff --git a/gateway-ha/src/main/resources/assets/css/common.css b/gateway-ha/src/main/resources/assets/css/common.css deleted file mode 100644 index 6382d00d2..000000000 --- a/gateway-ha/src/main/resources/assets/css/common.css +++ /dev/null @@ -1,28 +0,0 @@ -.tablink:hover { - background-color: #777; -} - -.tablink { - background-color: #555; - color: white; - float: left; - border: none; - outline: none; - cursor: pointer; - padding: 14px 16px; - font-size: 17px; - width: 25%; -} - - -.tabcontent { - padding: 70px 20px; - height: 100%; -} - - -body, html { - height: 100%; - margin: 0; - font-family: Arial; -} \ No newline at end of file diff --git a/gateway-ha/src/main/resources/assets/css/jquery.dataTables.min.css b/gateway-ha/src/main/resources/assets/css/jquery.dataTables.min.css deleted file mode 100644 index 6565b406d..000000000 --- a/gateway-ha/src/main/resources/assets/css/jquery.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}} diff --git a/gateway-ha/src/main/resources/assets/img/favicon.ico b/gateway-ha/src/main/resources/assets/img/favicon.ico deleted file mode 100644 index 6fbfd23f6db6d10b93807e5f16f29b3a07caa30c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32038 zcmeHQ3v`^tbzWPx<))3kTfApNQ)B^nx>^CZOQ3LlOCreg*H7YIpL%v z0V0DjmUdT`kqO`j#(;}m40a$O@Kd%dzp-RXwroqbWb6Ifm8|z;_xAf{{#osNS6(Z| zh&ktK_Md;|-tW%qpMUP$UpCt)+Zfxzg*L?VZ8v|zX1mK~v)y{DzTWsLo9$;vn?K*W zPP5r&Jz%q?A!hyu#@KAT9=6$TMj5cMrGuER!a^Oz``3BhyJ?_Bpe>+6kX$1~ti(+0 zsF|S!=e%vudt18my7$~5=zL8Rbbv0cBZ?*Funt5DMrA&e^-uKyK%p-Ozso5OsylrXM(G=dA-!W_Ne2|P# zn(vsI{~$<4C_(pv-5}^cB5Ai{#(p<~7q--EvwSQ;#GrD^aW=VpOoCMdAq;^Lk{{Uson9FHyV!<)O>Tl|Z{lk&=e!_AS#jVN{M}kza#AQ^AJ1%+Yk~lDK5|y2Bd16SA3Z59c{;a6n zpVTKTJ5lV8)FNO=j4oII9=BH7A2!txWsKc!e4 z@zTUI;xIJ1#8-~`mu>A9#+&Y{Re29JgZK~W8!I9|K*FmI&e%li{CZEejX{bRd~b!85_TawFBzU)FIQN z;);fu_fUS-%@wls-a5sT*uwKWh4k>0Gq+3{iuxi!SNE8Qa@f}4^kjO;i(L_U@P=bT znG`(U8jy$e!afuUTf}tex$74#!t(xsGQyT&J%=OkxtQ1M&m!PAbzOB+rE2eRdIw~V zap4$W9-_Y~lKbPP@c6=DUVmFvh~9<|Wkk|b^$qq9Kic%II#V=k%=XHeb1tI1u!SNd zI>w)isK2h~3jx^tahl(`_ccY}u9GRl3Jp`XW-u1UthaG$V3@O9E%;0Z~3yuwcLf&Y7n(sEuAFGc1F$4{roYS-$;)(M;W=45vjcD8{}_jT%{=%Hs*ZBysU>S5gd>gt^Fy3d3^W`PQ_+hpUNjXtuEgFZ2El6ON7(ipH zgT)107c6d9`J?I2dxj_TM+x;9u`z;!`7+8^a&>TmI8{%FAt zd9m^YmuH!cUynZb^L~hKA^KuoO$wsX^}*r-t_#vTRGHZNYrf1ME!ZJ1R-WMUEVJ?J z(f3_A2NC1ZGk!MSaQSNkA`Eo^pAHuN5f|Bg?nCv z(=$?<;S(+%F8zt+O7ww5+nzY0h2hkH{jKh}#&#rpoEH)q_ohEY;?MNq)SvP%w+=Wz zvaHb|k@#xrPuzSSL|b16<11O$b4A+S)EV125`|lfm~vM-<~&B-!aeWU-n_@Uy3%q# zsQg$TiO%gGRNX$p75-iPqk0+EdU227`lar>N3j0X{lO8eKXso!g7u$I9}wujZUokW z@_(`PPlNs=X&$7mKL01H4i=7}KCqBF2M6fCXav;3qF}xKuc1Ht!H01yP^X3dx<>kq ze4G!`KP2@)y{SvUc#ovJe>%&6I3~7$3PIP(dnU0GGqFe2ThgiVC>hX--_fJvkGJYL zwNl5)c{)x?*YT*}SSNq<_m5Qr!S!#h^E7~@N*yPgb~Np3+S#-_zY}pQXc5Tworndv zh!C9fc8umN=k?ph;oAzggK|JcpdQfG`aT3@69ci_PHYOJh1ICyoU>D7pSOJhz6J0q zzKhTe0_JUAE9UR3MFvB+!Ul{=2ZMReE{%Qe&O7jZf(zC+3OtBOUhDd5e!GAe3?AYD z#+`R)9W3m#cio8Z3)EQO80bap{Q!P%fS8Dl-$JNy0<+R#?(QV`%x|{7572iFd?!F- zBxYcTfBW5*kNdzi{B{?ire|`abw}hoe7=&%1?{*bAy1GvQ}F1V3}< ztik;D>F`gVVfm=fD!{iIcyI9jQ1}iluaZ#>A8GH9{G_KHlw}k5OUC2_Vo#%wHT{ea zs^7~d9>6{7azLCj|0w>~-l6(9JEtF!SHBIvjHQiIw8kwJ+qGi-X%L8s*@ML zQYsmf4oharL2=HY|L_&?qmIghzSFUZxHD4@$ukR1z?Q1d=X(c&twkbzI66|e$|X4; zKaRFI1RdZ590&i)&J(APt#j)8k~#UPto(Sf)Ev}4C?2Tcg$tP%E=?p)zgN5i+NZ2) zZ@1)JUo7@1M}=h*_J@sxGfp2_XIi0TPC5qsC#Cj~_Mh?~VjB><3DjqxPwP;$$}P*r z(HA&zU);$4u;F}MkE70xi#?@C?2|P)@H=y2A@HA)x+5BYNdM8Wp^(;w?eoIt%T+l? znwCSpjxq9Q%ePm` zTR*Im?f=!N{3>_+cQeMW1saj*Q)jny$kVgS<=F2oVUB8(E&o)5x;PCy!~!4VAo;u| z2FIilS(;P~AI5Td{kt`CB)b)Uhqb5+=#}d48%lpnP0o~3dCGQD=WA}M zl=JU)tA20#JY&vDm#XxHq{g&0H&tx!l(nC&l3t@5@?PBCEzd7FCz;9c&zv$SpE!tt z>CTihviH#z>8SIlIf63w!ykPy@GYN4pHHit<=f|+bXx2a&{w9GOH+xSAJzO~jm@T# zetGVON+p}TIL~-Ec0rtXf`b_wmB7FH(^Wn@HF+|e-GZ~%$?%bdTt&d)oQ!rETPn}a zKPMMx<)ycu9v@f7P zPBYgi0VY2#0`b=j;s+j&HNWOR;+Ds47*A>E#5t)PeYZ^B`WIb)9={`JW^UO3IPsrV zSc#cre5bOeRN&Ql&|g*QZsF;L3)c&utC7PF?aLK_UjYYR-Ne?_AbzedR^L=Rh#x!+ z{`Xh51An2Ip**dKpSs~6)o z6u*&?_sdrK{k_fTYet!1{B;5NO}V-wee&Lax+U-7R#|^ry=13W;o0Y_f`A{#e%B#6 zv#TXD3I2-7!0+?ff{)U;i|B(@zz=^x%U>=S|JqyXQUCf}EbHI2K`+#OZb1#&@}krq z)e5LSZswnDJ+k`7`T+d?z*Ij)!rouEseJzTjGkvUcT0xt0D!M#jIOF+6@?8?66J z^86Xm6S#?8$JUz8eGDpF$X^g*b6MS5f>LqJJJ@C`tNMj7e-wgcP7bBql z75*mRZvg&q{ijz}FKCVfe>?DpKVR6_;Z@I%H^0}4cBmC+vc^o@#y=%1xdHg`O#{nc zgwJ2o$2or2-rO>XAAQI4O`e}xeM7S>pV$~4|9iyW5+1+mKdOt!o`*Z+`T1e|?%2I_ z7n8St&?Zj+qjRjEUyZeQo;9us_~GyKTV2N?_-}H_;Y|I#1Y!@w?~>&cnj_%vgMO|6 z{H9-5yxS`;ebFti{$;B?GqXir`ZKqWuhvRqH}&|3?_UD`Msbb_-S3Zy|7MpQ%Fy_^ z1~BV@?q<~gCpG@sL%RR)y@14UJ{R~G1mU;l$dVVk@yu$J%+XD<4E6Z(m)vSiqDxwT zQTJvXTsD3@``4iUk3Fr|B&z&BPs=a+eswwD`irij# zc3z8QB{$27HQiEoxL>OF;6A7k=gyDiz^5Jc>ngK! z$iA>sw}F{|R1*NR8ZUnBV&=BqOI|fMMd~yDGKLes1MQQ6dRz4gmoya*j&T8IgWbfY z&r`SEzv#fY#&?|JsI#c}vBr7j&)upY#KX(KUd(T{J^SCY*SqBWAFK(~ufGtl>HDqc zJhJ8Q+ti#&-3^auvEk2W$WHhqzWd{LteZfXb8_!%m*=i;QFRzEzi_gg&>;iFfIZGv~0D(*w#sqWsNX+40j3$;Pvgx<>2o;rKI+?ac8OOlFRWR4(3hg$ekHk8?if zsFl;^=#^$ z=d|X77J_`|w9;@96maGSTyZ|@x^3g}e{1ds9Rzg_!~d`$Px6M0ZR3?pBYW=7c{u-* zZ~gxmj};Hc|C7x$O%-ZvibJiaG zKZ!m4Ae_?}UZM=jvSdDlvo6Q1^Da1h5_;~%Icp!V>U8@I{GPo}vgYDE3C@&+%O7W& zk#)>5{eTCAvnrwF#Cea5l>M@F{C=_HEC|njWK20AOOp0UX4-yWz*&$m<>E@COv;Y% zEqCYi!;p1Q)_lH1N?vix#l4-_N9>mJx7#Iuah#x`2^_@egJ>0Fo#hiLfm1EgR=LwusizI70_)iTwvycM&H!1Z5Y z;fvTg^#tx0;k~j@meJnscTas!8}@Gd#FHpnDu?VY>8SOny~wh+I%MT_<+AOk4f6go zZaMHIFyM>;gR!6PeWY1-!-iV9t4rSa$7*DTwVwGX7uhTyl!vu`o$McXEb>z(`R z@eWNpH~3CDjWY(PaF(G#xF5^V)8s8-)~)V@|8jPjmP_7b1RpulrrErBd>kO`ZgTI(>~nog8W(MC37t7ypZjf z0DJwIa(s92f^RRF{LjA8CGS0;?FMGwi(`QMNepJMc;92Ka%#iix3GBD;psUS(AH(J ztHEBrQ}0b1+o<~9!F1T%#?np;+h}qn_L?hX#dO%>En7DEvz_1hH>*7?yYRtfZL;HM zes*Z&%YUp*PFnKSo;2{4zu7H^otI?Ir(vJPUY!ZF*KGY>GxlmKm0UZ%QEDGsg}s$3 zSuu6c7R~&no4Vv3e241F8w(X~Xdo}d`ipwY8^dZ-o0m&NAy(HM0Ae(#4+}m1_GH8o4^54cDK109N zz23a{lCq`vr|tb!r<^kKQTN2P<-2Xz*K^5>f9l5hA;rRHKjQaFoY=codqdn?i6sBk z9@&OHLI!hYhIlr7)wGG`oBv3soP62RpW_2Vc=hL6QM z3}&p>9Ox6;YN$Wn6*NWAzXJ9l?)e#;25lU)WwEVH8f_l54Q{>1>L;AO28WxH&1D*dyd>@&vc1eT?~xZVagUXOy0XpL4^(VTsi!vd06**; zDC5%|LSI{N}}S^l$3J{J}hU%{|IZcecrE zf7K?Nztbi!e>wi|q9_d5e_qCK4BpYIY|Y14b*nzI0eonupgk{=Y=ejS3~?XWq{kDJ zH`|Bhm3_;K*@u`OMK<>klq|NTkJ#2$`cPt)SAB&s_kE-Dq3mN8e;~OkS5$PevAHbDuBIlFf93?Q;0WDns5zHf5T9x_S7W4`TV@mQNX!rQSagtM_lj z<3aa>4uU#Cv2+>geexu4%24m$h(}@HATuV#C*Jq!tWvU|KfRd z8p=*R;^A3)(vndJ{z*>3SA<3GFGwHbRNYnY$8GHT@G?q=pS>f?~ zhdLoy(~9LlMzge5^s9Avw`)M2yRlT3j^bHzzGETpgd%lq{?|>$n3J;lGv%=7_eYpD*wHH4)d%CzpcjSE_raR$nX}-e9on8p~}9Cd1>X0W?7Fk^}ROhd8eLj;KOyqQ{Y28^X6~2$%<(KwqDL@ z?OZ3|dFWMZzcBL)dGUEk`)h{gZ}!RCQ9g$Select entity to edit" - + "" + "
" - + "" - + "
" - + "
"; - - $("#entity-editor-place-holder").html(html); - - var database = $("#databaseOverride").val(); - var readEntityUrl = "/entity"; - var getParameters = ""; - if (database) { - getParameters = {"useSchema": database} - } - submitData(readEntityUrl, getParameters, "get").done(function (data) { - var select = ""; - for (var i in data) { - select += ""; - } - $("#entityTypeSelector").html(select); - }); -} - -function renderEntitySelector() { - var entityType = $("#entityTypeSelector").find(':selected').val(); - - clear(); - $("#entitySelector").empty(); - entityData = ""; - - var database = $("#databaseOverride").val(); - var getParameters = ""; - if (database) { - getParameters = {"useSchema": database} - } - if (entityType !== 'select') { - submitData("/entity/" + entityType, getParameters, "get").done(function (data) { - entityData = data; - var select = ""; - for (var i in data) { - select += ""; - } - $("#entitySelector").html(select); - }); - } - renderEntityEditor() -} - -function buildNameForEntity(entity, entityType) { - switch (entityType) { - case "GATEWAY_BACKEND": - case "RESOURCE_GROUP": - return entity.name; - case "SELECTOR": - return entity.resourceGroupId; - default: - console.log("entity type not found : " + entityType); - return entity[0]; - } -} - -function renderEntityEditor() { - clear(); - var entityType = $("#entityTypeSelector").find(':selected').val(); - var element = document.getElementById("entityDetails"); - editor = new JSONEditor(element, {schema: {type: "object"}}); - var entity = ""; - var entityId = $("#entitySelector").find(':selected').val(); - for (var i in entityData) { - if (buildNameForEntity(entityData[i], entityType) == entityId) { - entity = entityData[i]; - } - } - - editor.set(entity); - - var submitHtml = "

"; - $("#entityEditorBottom").html(submitHtml); - - var entityDetailsTextArea = $("#entityDetailsTextArea"); - entityDetailsTextArea.html(""); - entityDetailsTextArea.append("

"); -} - -function updateObject() { - var entityType = $("#entityTypeSelector").find(':selected').val(); - var jsonVal = JSON.stringify(editor.get()); - - var database = $("#databaseOverride").val(); - var updateParams = {"entityType":entityType }; - if (database) { - updateParams["useSchema"] = database; - } - submitData("/entity?" + $.param(updateParams), jsonVal, "post").done(function (data) { - console.log(data); - renderEntitySelector(); - }) -} - -function loadToEditor() { - editor.set(JSON.parse($("#jsonTextArea").val())); -} - -function clear() { - $("#entityDetails").empty(); - $("#entityDetailsTextArea").empty(); - $("#entityEditorBottom").empty(); -} diff --git a/gateway-ha/src/main/resources/assets/js/hbar-chart.js b/gateway-ha/src/main/resources/assets/js/hbar-chart.js deleted file mode 100644 index 3aad376b5..000000000 --- a/gateway-ha/src/main/resources/assets/js/hbar-chart.js +++ /dev/null @@ -1,107 +0,0 @@ -(function($) { - "use strict"; - $.fn.hBarChart = function(customConfig) { - var config = $.extend({ - bgColor: 'green', - textColor: '#fff', - show: 'label', - sorting: true, - maxStyle: { - bg: 'orange', - text: 'white' - } - }, customConfig); - var chartObj = $(this); - var data = []; - var max = null; - var bgColor = config.bgColor; - var lightenDarkenColor = function(col, amt) { - var usePound = false; - if (col[0] == "#") { - col = col.slice(1); - usePound = true; - } - var num = parseInt(col, 16); - var r = (num >> 16) + amt; - if (r > 255) r = 255; - else if (r < 0) r = 0; - var b = ((num >> 8) & 0x00FF) + amt; - if (b > 255) b = 255; - else if (b < 0) b = 0; - var g = (num & 0x0000FF) + amt; - if (g > 255) g = 255; - else if (g < 0) g = 0; - return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16); - } - //end sorting operation - if (config.sorting) { - var sort_li = function(a, b) { - return ($(b).data('data')) > ($(a).data('data')) ? 1 : -1; - } - chartObj.find("li").sort(sort_li) // sort elements - .appendTo(chartObj); // append again to the list - } - //end sorting operation - //global style - chartObj.find("li").css({ - listStyleType: 'none', - padding: '5px', - boxSizing: 'border-box', - marginTop: '3px', - width: '100%', - background: config.bgColor, - color: config.textColor, - whiteSpace: 'nowrap', - borderRadius: '4px', - fontSize: '13px', - fontFamily: 'Tahoma, Geneva, sans-serif' - }) - //global style - //find max - chartObj.find("li").each(function() { - var val = $(this).data('data'); - data.push(val); - }); - max = Math.max.apply(Math, data); - // find max - chartObj.find("li").each(function() { - var lbl = $(this).text(); - var val = $(this).data('data'); - var percentage = (100 / max) * val; - bgColor = lightenDarkenColor(bgColor, 10); - // bar animation - $(this).css({ - width: 0, - background: bgColor - }); - $(this).animate({ - width: percentage + '%' - }, 1000) - // bar animation - //show label - switch (config.show) { - case 'label': - $(this).text(lbl); - break; - case 'data': - $(this).text(val); - break; - case 'both': - $(this).text(lbl).append(' (' + val + ')'); - break; - default: - break; - } - // end show label - // max style - if (val == max) { - $(this).css({ - background: config.maxStyle.bg, - color: config.maxStyle.text - }) - } - // max style - }); - } - //end plugin function -}(jQuery)); \ No newline at end of file diff --git a/gateway-ha/src/main/resources/assets/js/jquery-3.3.1.js b/gateway-ha/src/main/resources/assets/js/jquery-3.3.1.js deleted file mode 100644 index 9b5206bcc..000000000 --- a/gateway-ha/src/main/resources/assets/js/jquery-3.3.1.js +++ /dev/null @@ -1,10364 +0,0 @@ -/*! - * jQuery JavaScript Library v3.3.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2018-01-20T17:24Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - - - - var preservedScriptAttributes = { - type: true, - src: true, - noModule: true - }; - - function DOMEval( code, doc, node ) { - doc = doc || document; - - var i, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - if ( node[ i ] ) { - script[ i ] = node[ i ]; - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.3.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - div.style.position = "absolute"; - scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - ) ); - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - val = curCSS( elem, dimension, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox; - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = valueIsBorderBox && - ( support.boxSizingReliable() || val === elem.style[ dimension ] ); - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - if ( val === "auto" || - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { - - val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; - - // offsetWidth/offsetHeight provide border-box values - valueIsBorderBox = true; - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra && boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ); - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && support.scrollboxSize() === styles.position ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = Date.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - -<#include "header.ftl"> -

!!Admin ONLY!!

- -
- Override the Database (Optional): - - -
-
- -<#include "footer.ftl"> diff --git a/gateway-ha/src/main/resources/template/footer.ftl b/gateway-ha/src/main/resources/template/footer.ftl deleted file mode 100644 index 17c7245b6..000000000 --- a/gateway-ha/src/main/resources/template/footer.ftl +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/gateway-ha/src/main/resources/template/gateway-view.ftl b/gateway-ha/src/main/resources/template/gateway-view.ftl deleted file mode 100644 index c0214ad90..000000000 --- a/gateway-ha/src/main/resources/template/gateway-view.ftl +++ /dev/null @@ -1,93 +0,0 @@ -<#-- @ftlvariable name="" type="io.trino.gateway.ha.resource.GatewayViewResource$GatewayView" --> -<#setting datetime_format = "MM/dd/yyyy hh:mm:ss a '('zzz')'"> - - - - - - - - - - - - - - -<#include "header.ftl"> -
- Started at : - -
- -
-

All backends:

- - - - - - - - <#if backendStates?keys?size != 0> - - - - <#list backendConfigurations as bc> - - - - - - <#if backendStates?keys?size != 0 && backendStates[bc.name]??> - - - -
NameUrlGroupActiveQueued - Running - -
${bc.name}${bc.externalUrl} ${bc.routingGroup} ${bc.active?c} ${backendStates[bc.name].state()["QUEUED"]} - ${backendStates[bc.name].state()["RUNNING"]} - -
-
- -<#include "footer.ftl"> \ No newline at end of file diff --git a/gateway-ha/src/main/resources/template/header.ftl b/gateway-ha/src/main/resources/template/header.ftl deleted file mode 100644 index 9bab26036..000000000 --- a/gateway-ha/src/main/resources/template/header.ftl +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -
-

Trino Gateway

-
User: ${displayName}log out
- - - - - - - - - - - - -
diff --git a/gateway-ha/src/main/resources/template/login-form.ftl b/gateway-ha/src/main/resources/template/login-form.ftl deleted file mode 100644 index 4b6016c6d..000000000 --- a/gateway-ha/src/main/resources/template/login-form.ftl +++ /dev/null @@ -1,51 +0,0 @@ -<#-- @ftlvariable name="" type="io.trino.gateway.ha.resource.GatewayViewResource$GatewayView" --> -<#setting datetime_format = "MM/dd/yyyy hh:mm:ss a '('zzz')'"> - - - - - - - - - - - - - - -
-

Trino Gateway

-
-
-
- - -
-
- - -
-
- - -
-
- - -<#include "footer.ftl"> \ No newline at end of file diff --git a/gateway-ha/src/main/resources/template/query-history-view.ftl b/gateway-ha/src/main/resources/template/query-history-view.ftl deleted file mode 100644 index 836bc6684..000000000 --- a/gateway-ha/src/main/resources/template/query-history-view.ftl +++ /dev/null @@ -1,99 +0,0 @@ -<#setting datetime_format = "MM/dd/yyyy hh:mm:ss a '('zzz')'"> - - - - - - - - - - - - - - -<#include "header.ftl"> -
- Started at : - -
- -<#if queryHistory?size != 0> -
Query details [history size = ${queryHistory?size}]
-
- - - - - - - - - - - - - <#list queryHistory as q> - - - - - - - - - - -
queryIdroutedTousersourcequeryTextsubmissionTime
${q.queryId} ${q.backendUrl} - <#if q.user??> - ${q.user} - - - <#if q.source??> - ${q.source} - - ${q.queryText} - -
-
- -

Query history distribution

-
    - <#list queryDistribution?keys as cluster> -
  • - ${cluster?string} => ${queryDistribution[cluster]?string} -
  • - -
-
- - -<#include "footer.ftl"> - diff --git a/gateway-ha/src/test/java/io/trino/gateway/ha/security/TestLbAuthenticator.java b/gateway-ha/src/test/java/io/trino/gateway/ha/security/TestLbAuthenticator.java index 628e81972..473e68958 100644 --- a/gateway-ha/src/test/java/io/trino/gateway/ha/security/TestLbAuthenticator.java +++ b/gateway-ha/src/test/java/io/trino/gateway/ha/security/TestLbAuthenticator.java @@ -20,6 +20,8 @@ import io.trino.gateway.ha.config.FormAuthConfiguration; import io.trino.gateway.ha.config.SelfSignKeyPairConfiguration; import io.trino.gateway.ha.config.UserConfiguration; +import io.trino.gateway.ha.domain.R; +import io.trino.gateway.ha.domain.request.RestLoginRequest; import jakarta.ws.rs.core.NewCookie; import jakarta.ws.rs.core.Response; import org.junit.jupiter.api.Test; @@ -29,6 +31,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -103,7 +106,7 @@ public void testPresetUsers() "user1", new UserConfiguration("priv1, priv2", "pass1"), "user2", new UserConfiguration("priv2, priv2", "pass2")); - LbFormAuthManager authentication = new LbFormAuthManager(null, presetUsers); + LbFormAuthManager authentication = new LbFormAuthManager(null, presetUsers, new HashMap<>()); assertThat(authentication.authenticate(new BasicCredentials("user1", "pass1"))) .isTrue(); @@ -117,7 +120,7 @@ public void testPresetUsers() public void testNoLdapNoPresetUsers() throws Exception { - LbFormAuthManager authentication = new LbFormAuthManager(null, null); + LbFormAuthManager authentication = new LbFormAuthManager(null, null, null); assertThat(authentication.authenticate(new BasicCredentials("user1", "pass1"))) .isFalse(); } @@ -126,7 +129,7 @@ public void testNoLdapNoPresetUsers() public void testWrongLdapConfig() throws Exception { - LbFormAuthManager authentication = new LbFormAuthManager(null, null); + LbFormAuthManager authentication = new LbFormAuthManager(null, null, null); assertThat(authentication.authenticate(new BasicCredentials("user1", "pass1"))) .isFalse(); } @@ -156,12 +159,15 @@ public void testLoginForm() "user1", new UserConfiguration("priv1, priv2", "pass1"), "user2", new UserConfiguration("priv2, priv2", "pass2")); - LbFormAuthManager lbFormAuthManager = new LbFormAuthManager(formAuthConfig, presetUsers); - Response response = lbFormAuthManager.processLoginForm("user1", "pass1"); - NewCookie cookie = response.getCookies().get(OAUTH_ID_TOKEN); - String value = cookie.getValue(); - assertThat(value != null && value.length() > 0).isTrue(); - log.info(cookie.getValue()); - JWT.decode(value); + LbFormAuthManager lbFormAuthManager = new LbFormAuthManager(formAuthConfig, presetUsers, new HashMap<>()); + RestLoginRequest restLoginRequest = new RestLoginRequest(); + restLoginRequest.setUsername("user1"); + restLoginRequest.setPassword("pass1"); + R r = lbFormAuthManager.processRESTLogin(restLoginRequest); + assertThat(R.isSuccess(r)).isTrue(); + Map data = (Map) r.getData(); + String token = (String) data.get("token"); + log.info(token); + JWT.decode(token); } } diff --git a/webapp/.env b/webapp/.env new file mode 100644 index 000000000..5be413018 --- /dev/null +++ b/webapp/.env @@ -0,0 +1,4 @@ +# https://vitejs.dev/guide/env-and-mode.html + +VITE_GLOB_APP_TITLE="Trino Gateway" +VITE_GLOB_APP_SHORT_NAME="TrinoGateway" diff --git a/webapp/.env.development b/webapp/.env.development new file mode 100644 index 000000000..993f5dc7a --- /dev/null +++ b/webapp/.env.development @@ -0,0 +1,4 @@ +# https://vitejs.dev/guide/env-and-mode.html + +VITE_BASE_URL=http://127.0.0.1:8090/ +VITE_PROXY_PATH=/api diff --git a/webapp/.env.production b/webapp/.env.production new file mode 100644 index 000000000..4ddad222f --- /dev/null +++ b/webapp/.env.production @@ -0,0 +1,3 @@ +# https://vitejs.dev/guide/env-and-mode.html + +VITE_BASE_URL=/ diff --git a/webapp/.eslintrc.cjs b/webapp/.eslintrc.cjs new file mode 100644 index 000000000..9d6dfe5f7 --- /dev/null +++ b/webapp/.eslintrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + "@typescript-eslint/no-explicit-any": "off", + "react-hooks/exhaustive-deps": "off" + }, +} diff --git a/webapp/.gitignore b/webapp/.gitignore new file mode 100644 index 000000000..147d9ad3d --- /dev/null +++ b/webapp/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +node diff --git a/webapp/README.md b/webapp/README.md new file mode 100644 index 000000000..01b81e543 --- /dev/null +++ b/webapp/README.md @@ -0,0 +1,26 @@ + +# Framework document +1. Semi UI: https://semi.design/en-US + - If you want to customize the theme, you can view https://semi.design/dsm/landing +2. Vite: https://vitejs.dev/ +3. React: https://react.dev/ +4. TypeScript: https://www.typescriptlang.org/ +5. Echarts: https://echarts.apache.org/ + +# Development +``` +pnpm install +pnpm run dev +pnpm run build +``` + +# Package +``` +# If you want the web to start with the project, you can execute +./mvnw clean install + +# If you want to run the web project alone, you can execute +cd ./webapp +pnpm install +pnpm run build +``` diff --git a/webapp/index.html b/webapp/index.html new file mode 100644 index 000000000..d52a6870e --- /dev/null +++ b/webapp/index.html @@ -0,0 +1,13 @@ + + + + + + + Trino Gateway + + +
+ + + diff --git a/webapp/package.json b/webapp/package.json new file mode 100644 index 000000000..d8fe80568 --- /dev/null +++ b/webapp/package.json @@ -0,0 +1,41 @@ +{ + "name": "trino-gateway", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@douyinfe/semi-icons": "^2.47.1", + "@douyinfe/semi-icons-lab": "^2.47.1", + "@douyinfe/semi-illustrations": "^2.47.1", + "@douyinfe/semi-ui": "^2.47.1", + "echarts": "^5.4.3", + "js-cookie": "^3.0.5", + "moment": "^2.29.4", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.0", + "sass": "^1.69.5", + "zustand": "^4.3.8" + }, + "devDependencies": { + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "@vitejs/plugin-react": "^4.2.0", + "eslint": "^8.53.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "typescript": "^5.2.2", + "vite": "^5.0.0", + "vite-plugin-svgr": "^4.2.0", + "@types/echarts": "^4.9.22", + "@types/js-cookie": "^3.0.6" + } +} diff --git a/webapp/pnpm-lock.yaml b/webapp/pnpm-lock.yaml new file mode 100644 index 000000000..32082fc13 --- /dev/null +++ b/webapp/pnpm-lock.yaml @@ -0,0 +1,3265 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@douyinfe/semi-icons': + specifier: ^2.47.1 + version: registry.npmmirror.com/@douyinfe/semi-icons@2.47.1(react@18.2.0) + '@douyinfe/semi-icons-lab': + specifier: ^2.47.1 + version: registry.npmmirror.com/@douyinfe/semi-icons-lab@2.47.1(react-dom@18.2.0)(react@18.2.0) + '@douyinfe/semi-illustrations': + specifier: ^2.47.1 + version: registry.npmmirror.com/@douyinfe/semi-illustrations@2.47.1(react@18.2.0) + '@douyinfe/semi-ui': + specifier: ^2.47.1 + version: registry.npmmirror.com/@douyinfe/semi-ui@2.47.1(react-dom@18.2.0)(react@18.2.0) + echarts: + specifier: ^5.4.3 + version: registry.npmmirror.com/echarts@5.4.3 + js-cookie: + specifier: ^3.0.5 + version: registry.npmmirror.com/js-cookie@3.0.5 + moment: + specifier: ^2.29.4 + version: registry.npmmirror.com/moment@2.29.4 + react: + specifier: ^18.2.0 + version: registry.npmmirror.com/react@18.2.0 + react-dom: + specifier: ^18.2.0 + version: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + react-router-dom: + specifier: ^6.20.0 + version: registry.npmmirror.com/react-router-dom@6.20.0(react-dom@18.2.0)(react@18.2.0) + sass: + specifier: ^1.69.5 + version: registry.npmmirror.com/sass@1.69.5 + zustand: + specifier: ^4.3.8 + version: registry.npmmirror.com/zustand@4.3.8(react@18.2.0) + +devDependencies: + '@types/echarts': + specifier: ^4.9.22 + version: registry.npmmirror.com/@types/echarts@4.9.22 + '@types/js-cookie': + specifier: ^3.0.6 + version: registry.npmmirror.com/@types/js-cookie@3.0.6 + '@types/react': + specifier: ^18.2.37 + version: registry.npmmirror.com/@types/react@18.2.37 + '@types/react-dom': + specifier: ^18.2.15 + version: registry.npmmirror.com/@types/react-dom@18.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ^6.10.0 + version: registry.npmmirror.com/@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0)(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': + specifier: ^6.10.0 + version: registry.npmmirror.com/@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@vitejs/plugin-react': + specifier: ^4.2.0 + version: registry.npmmirror.com/@vitejs/plugin-react@4.2.0(vite@5.0.0) + eslint: + specifier: ^8.53.0 + version: registry.npmmirror.com/eslint@8.53.0 + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: registry.npmmirror.com/eslint-plugin-react-hooks@4.6.0(eslint@8.53.0) + eslint-plugin-react-refresh: + specifier: ^0.4.4 + version: registry.npmmirror.com/eslint-plugin-react-refresh@0.4.4(eslint@8.53.0) + typescript: + specifier: ^5.2.2 + version: registry.npmmirror.com/typescript@5.2.2 + vite: + specifier: ^5.0.0 + version: registry.npmmirror.com/vite@5.0.0(sass@1.69.5) + vite-plugin-svgr: + specifier: ^4.2.0 + version: registry.npmmirror.com/vite-plugin-svgr@4.2.0(typescript@5.2.2)(vite@5.0.0) + +packages: + + registry.npmmirror.com/@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz} + name: '@aashutoshrathi/word-wrap' + version: 1.2.6 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.1.tgz} + name: '@ampproject/remapping' + version: 2.2.1 + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': registry.npmmirror.com/@jridgewell/gen-mapping@0.3.3 + '@jridgewell/trace-mapping': registry.npmmirror.com/@jridgewell/trace-mapping@0.3.20 + dev: true + + registry.npmmirror.com/@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.23.5.tgz} + name: '@babel/code-frame' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': registry.npmmirror.com/@babel/highlight@7.23.4 + chalk: registry.npmmirror.com/chalk@2.4.2 + dev: true + + registry.npmmirror.com/@babel/compat-data@7.23.5: + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.23.5.tgz} + name: '@babel/compat-data' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/core@7.23.5: + resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/core/-/core-7.23.5.tgz} + name: '@babel/core' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': registry.npmmirror.com/@ampproject/remapping@2.2.1 + '@babel/code-frame': registry.npmmirror.com/@babel/code-frame@7.23.5 + '@babel/generator': registry.npmmirror.com/@babel/generator@7.23.5 + '@babel/helper-compilation-targets': registry.npmmirror.com/@babel/helper-compilation-targets@7.22.15 + '@babel/helper-module-transforms': registry.npmmirror.com/@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5) + '@babel/helpers': registry.npmmirror.com/@babel/helpers@7.23.5 + '@babel/parser': registry.npmmirror.com/@babel/parser@7.23.5 + '@babel/template': registry.npmmirror.com/@babel/template@7.22.15 + '@babel/traverse': registry.npmmirror.com/@babel/traverse@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + convert-source-map: registry.npmmirror.com/convert-source-map@2.0.0 + debug: registry.npmmirror.com/debug@4.3.4 + gensync: registry.npmmirror.com/gensync@1.0.0-beta.2 + json5: registry.npmmirror.com/json5@2.2.3 + semver: registry.npmmirror.com/semver@6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@babel/generator@7.23.5: + resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/generator/-/generator-7.23.5.tgz} + name: '@babel/generator' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + '@jridgewell/gen-mapping': registry.npmmirror.com/@jridgewell/gen-mapping@0.3.3 + '@jridgewell/trace-mapping': registry.npmmirror.com/@jridgewell/trace-mapping@0.3.20 + jsesc: registry.npmmirror.com/jsesc@2.5.2 + dev: true + + registry.npmmirror.com/@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz} + name: '@babel/helper-compilation-targets' + version: 7.22.15 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': registry.npmmirror.com/@babel/compat-data@7.23.5 + '@babel/helper-validator-option': registry.npmmirror.com/@babel/helper-validator-option@7.23.5 + browserslist: registry.npmmirror.com/browserslist@4.22.1 + lru-cache: registry.npmmirror.com/lru-cache@5.1.1 + semver: registry.npmmirror.com/semver@6.3.1 + dev: true + + registry.npmmirror.com/@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz} + name: '@babel/helper-environment-visitor' + version: 7.22.20 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz} + name: '@babel/helper-function-name' + version: 7.23.0 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': registry.npmmirror.com/@babel/template@7.22.15 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz} + name: '@babel/helper-hoist-variables' + version: 7.22.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz} + name: '@babel/helper-module-imports' + version: 7.22.15 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz} + id: registry.npmmirror.com/@babel/helper-module-transforms/7.23.3 + name: '@babel/helper-module-transforms' + version: 7.23.3 + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@babel/helper-environment-visitor': registry.npmmirror.com/@babel/helper-environment-visitor@7.22.20 + '@babel/helper-module-imports': registry.npmmirror.com/@babel/helper-module-imports@7.22.15 + '@babel/helper-simple-access': registry.npmmirror.com/@babel/helper-simple-access@7.22.5 + '@babel/helper-split-export-declaration': registry.npmmirror.com/@babel/helper-split-export-declaration@7.22.6 + '@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20 + dev: true + + registry.npmmirror.com/@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz} + name: '@babel/helper-plugin-utils' + version: 7.22.5 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz} + name: '@babel/helper-simple-access' + version: 7.22.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz} + name: '@babel/helper-split-export-declaration' + version: 7.22.6 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz} + name: '@babel/helper-string-parser' + version: 7.23.4 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz} + name: '@babel/helper-validator-identifier' + version: 7.22.20 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz} + name: '@babel/helper-validator-option' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/@babel/helpers@7.23.5: + resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helpers/-/helpers-7.23.5.tgz} + name: '@babel/helpers' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': registry.npmmirror.com/@babel/template@7.22.15 + '@babel/traverse': registry.npmmirror.com/@babel/traverse@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/highlight/-/highlight-7.23.4.tgz} + name: '@babel/highlight' + version: 7.23.4 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20 + chalk: registry.npmmirror.com/chalk@2.4.2 + js-tokens: registry.npmmirror.com/js-tokens@4.0.0 + dev: true + + registry.npmmirror.com/@babel/parser@7.23.5: + resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/parser/-/parser-7.23.5.tgz} + name: '@babel/parser' + version: 7.23.5 + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz} + id: registry.npmmirror.com/@babel/plugin-transform-react-jsx-self/7.23.3 + name: '@babel/plugin-transform-react-jsx-self' + version: 7.23.3 + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@babel/helper-plugin-utils': registry.npmmirror.com/@babel/helper-plugin-utils@7.22.5 + dev: true + + registry.npmmirror.com/@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz} + id: registry.npmmirror.com/@babel/plugin-transform-react-jsx-source/7.23.3 + name: '@babel/plugin-transform-react-jsx-source' + version: 7.23.3 + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@babel/helper-plugin-utils': registry.npmmirror.com/@babel/helper-plugin-utils@7.22.5 + dev: true + + registry.npmmirror.com/@babel/runtime@7.23.5: + resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.5.tgz} + name: '@babel/runtime' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: registry.npmmirror.com/regenerator-runtime@0.14.0 + dev: false + + registry.npmmirror.com/@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/template/-/template-7.22.15.tgz} + name: '@babel/template' + version: 7.22.15 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': registry.npmmirror.com/@babel/code-frame@7.23.5 + '@babel/parser': registry.npmmirror.com/@babel/parser@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@babel/traverse@7.23.5: + resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.5.tgz} + name: '@babel/traverse' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': registry.npmmirror.com/@babel/code-frame@7.23.5 + '@babel/generator': registry.npmmirror.com/@babel/generator@7.23.5 + '@babel/helper-environment-visitor': registry.npmmirror.com/@babel/helper-environment-visitor@7.22.20 + '@babel/helper-function-name': registry.npmmirror.com/@babel/helper-function-name@7.23.0 + '@babel/helper-hoist-variables': registry.npmmirror.com/@babel/helper-hoist-variables@7.22.5 + '@babel/helper-split-export-declaration': registry.npmmirror.com/@babel/helper-split-export-declaration@7.22.6 + '@babel/parser': registry.npmmirror.com/@babel/parser@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + debug: registry.npmmirror.com/debug@4.3.4 + globals: registry.npmmirror.com/globals@11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@babel/types@7.23.5: + resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/types/-/types-7.23.5.tgz} + name: '@babel/types' + version: 7.23.5 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': registry.npmmirror.com/@babel/helper-string-parser@7.23.4 + '@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20 + to-fast-properties: registry.npmmirror.com/to-fast-properties@2.0.0 + dev: true + + registry.npmmirror.com/@dnd-kit/accessibility@3.1.0(react@18.2.0): + resolution: {integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz} + id: registry.npmmirror.com/@dnd-kit/accessibility/3.1.0 + name: '@dnd-kit/accessibility' + version: 3.1.0 + peerDependencies: + react: '>=16.8.0' + dependencies: + react: registry.npmmirror.com/react@18.2.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/@dnd-kit/core@6.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@dnd-kit/core/-/core-6.1.0.tgz} + id: registry.npmmirror.com/@dnd-kit/core/6.1.0 + name: '@dnd-kit/core' + version: 6.1.0 + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@dnd-kit/accessibility': registry.npmmirror.com/@dnd-kit/accessibility@3.1.0(react@18.2.0) + '@dnd-kit/utilities': registry.npmmirror.com/@dnd-kit/utilities@3.2.2(react@18.2.0) + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.1.0)(react@18.2.0): + resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@dnd-kit/sortable/-/sortable-7.0.2.tgz} + id: registry.npmmirror.com/@dnd-kit/sortable/7.0.2 + name: '@dnd-kit/sortable' + version: 7.0.2 + peerDependencies: + '@dnd-kit/core': ^6.0.7 + react: '>=16.8.0' + dependencies: + '@dnd-kit/core': registry.npmmirror.com/@dnd-kit/core@6.1.0(react-dom@18.2.0)(react@18.2.0) + '@dnd-kit/utilities': registry.npmmirror.com/@dnd-kit/utilities@3.2.2(react@18.2.0) + react: registry.npmmirror.com/react@18.2.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/@dnd-kit/utilities@3.2.2(react@18.2.0): + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz} + id: registry.npmmirror.com/@dnd-kit/utilities/3.2.2 + name: '@dnd-kit/utilities' + version: 3.2.2 + peerDependencies: + react: '>=16.8.0' + dependencies: + react: registry.npmmirror.com/react@18.2.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/@douyinfe/semi-animation-react@2.47.1: + resolution: {integrity: sha512-5BzuEHSOW06IbNotshB1RsUoq0oJdY9IpmbQQL77kmvu8DvKnIsGDeYWP6TYwoKycCCMIDyCYsD13s+qMUGvwg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.47.1.tgz} + name: '@douyinfe/semi-animation-react' + version: 2.47.1 + dependencies: + '@douyinfe/semi-animation': registry.npmmirror.com/@douyinfe/semi-animation@2.47.1 + '@douyinfe/semi-animation-styled': registry.npmmirror.com/@douyinfe/semi-animation-styled@2.47.1 + classnames: registry.npmmirror.com/classnames@2.3.2 + dev: false + + registry.npmmirror.com/@douyinfe/semi-animation-styled@2.47.1: + resolution: {integrity: sha512-jjEwbVMKaIh74A1svvLdSseGIiJYX0CiMisfiwWtp/f3OCJTB20CaIHrINGTti5R9bB/MD5Oe3GuHLoD6/JQMw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.47.1.tgz} + name: '@douyinfe/semi-animation-styled' + version: 2.47.1 + dev: false + + registry.npmmirror.com/@douyinfe/semi-animation@2.47.1: + resolution: {integrity: sha512-DG4bP3N3UZSeIoP4hDGFyKzNF83cd9vVjCJnxHUGTtVtFSpO1b47iQ0kD1qcgkUZghEqeixPFFu+6ilhq0qzZg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-animation/-/semi-animation-2.47.1.tgz} + name: '@douyinfe/semi-animation' + version: 2.47.1 + dependencies: + bezier-easing: registry.npmmirror.com/bezier-easing@2.1.0 + dev: false + + registry.npmmirror.com/@douyinfe/semi-foundation@2.47.1: + resolution: {integrity: sha512-2yO2kPO9TX+7gzRikmUy34CRckTB3Qkt+K9eIA2FMnIQ7R00yus7nAeoLaOaU8qUJd+OrqIEtwHGxthd0V1Wrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-foundation/-/semi-foundation-2.47.1.tgz} + name: '@douyinfe/semi-foundation' + version: 2.47.1 + dependencies: + '@douyinfe/semi-animation': registry.npmmirror.com/@douyinfe/semi-animation@2.47.1 + async-validator: registry.npmmirror.com/async-validator@3.5.2 + classnames: registry.npmmirror.com/classnames@2.3.2 + date-fns: registry.npmmirror.com/date-fns@2.30.0 + date-fns-tz: registry.npmmirror.com/date-fns-tz@1.3.8(date-fns@2.30.0) + lodash: registry.npmmirror.com/lodash@4.17.21 + memoize-one: registry.npmmirror.com/memoize-one@5.2.1 + scroll-into-view-if-needed: registry.npmmirror.com/scroll-into-view-if-needed@2.2.31 + dev: false + + registry.npmmirror.com/@douyinfe/semi-icons-lab@2.47.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UYAtDQjdHk3ymLAPmiHjk+XGLn6ppghpzRnMMxq7TUucJw8enysOM6lvr6bH34VNk0SKrzHBQyKgG7rhQL3gmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-icons-lab/-/semi-icons-lab-2.47.1.tgz} + id: registry.npmmirror.com/@douyinfe/semi-icons-lab/2.47.1 + name: '@douyinfe/semi-icons-lab' + version: 2.47.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + dev: false + + registry.npmmirror.com/@douyinfe/semi-icons@2.47.1(react@18.2.0): + resolution: {integrity: sha512-+gC22MWuOCKSRwB5Yxq55+NUgoO9b7stYvIkuCmPuD3kYgjFhhGRR+o9dscQmDa8Wjd98wY05zI01S4BV/ptLw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-icons/-/semi-icons-2.47.1.tgz} + id: registry.npmmirror.com/@douyinfe/semi-icons/2.47.1 + name: '@douyinfe/semi-icons' + version: 2.47.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + classnames: registry.npmmirror.com/classnames@2.3.2 + react: registry.npmmirror.com/react@18.2.0 + dev: false + + registry.npmmirror.com/@douyinfe/semi-illustrations@2.47.1(react@18.2.0): + resolution: {integrity: sha512-ouhdAHzcBEW5kv5EFvHQsITSHIxlL0mnCMz63TVIywGA6QnCcxyMG6er0rlChAnu76FhlERR/Ys5Dlf2e5VhSQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.47.1.tgz} + id: registry.npmmirror.com/@douyinfe/semi-illustrations/2.47.1 + name: '@douyinfe/semi-illustrations' + version: 2.47.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: registry.npmmirror.com/react@18.2.0 + dev: false + + registry.npmmirror.com/@douyinfe/semi-theme-default@2.47.1: + resolution: {integrity: sha512-GGWH6sBvwBft8eB+7V0VSueSVmsfLhabzSv/GXYwZeyljyuj4/JTRZa2qyiSgN1BOZbwn3vPW1si2QFioR0gQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.47.1.tgz} + name: '@douyinfe/semi-theme-default' + version: 2.47.1 + dependencies: + glob: registry.npmmirror.com/glob@7.2.3 + dev: false + + registry.npmmirror.com/@douyinfe/semi-ui@2.47.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HxYvjn32DJsDPmcspM8jzHMY84f4skEAN6Zheg4FPW74uAUSnGILj5HXd/vZM4c6bbJeQSnxP0Grqa5qrZFpkg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@douyinfe/semi-ui/-/semi-ui-2.47.1.tgz} + id: registry.npmmirror.com/@douyinfe/semi-ui/2.47.1 + name: '@douyinfe/semi-ui' + version: 2.47.1 + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + dependencies: + '@dnd-kit/core': registry.npmmirror.com/@dnd-kit/core@6.1.0(react-dom@18.2.0)(react@18.2.0) + '@dnd-kit/sortable': registry.npmmirror.com/@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.1.0)(react@18.2.0) + '@dnd-kit/utilities': registry.npmmirror.com/@dnd-kit/utilities@3.2.2(react@18.2.0) + '@douyinfe/semi-animation': registry.npmmirror.com/@douyinfe/semi-animation@2.47.1 + '@douyinfe/semi-animation-react': registry.npmmirror.com/@douyinfe/semi-animation-react@2.47.1 + '@douyinfe/semi-foundation': registry.npmmirror.com/@douyinfe/semi-foundation@2.47.1 + '@douyinfe/semi-icons': registry.npmmirror.com/@douyinfe/semi-icons@2.47.1(react@18.2.0) + '@douyinfe/semi-illustrations': registry.npmmirror.com/@douyinfe/semi-illustrations@2.47.1(react@18.2.0) + '@douyinfe/semi-theme-default': registry.npmmirror.com/@douyinfe/semi-theme-default@2.47.1 + async-validator: registry.npmmirror.com/async-validator@3.5.2 + classnames: registry.npmmirror.com/classnames@2.3.2 + copy-text-to-clipboard: registry.npmmirror.com/copy-text-to-clipboard@2.2.0 + date-fns: registry.npmmirror.com/date-fns@2.30.0 + date-fns-tz: registry.npmmirror.com/date-fns-tz@1.3.8(date-fns@2.30.0) + lodash: registry.npmmirror.com/lodash@4.17.21 + prop-types: registry.npmmirror.com/prop-types@15.8.1 + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + react-resizable: registry.npmmirror.com/react-resizable@3.0.5(react-dom@18.2.0)(react@18.2.0) + react-window: registry.npmmirror.com/react-window@1.8.10(react-dom@18.2.0)(react@18.2.0) + resize-observer-polyfill: registry.npmmirror.com/resize-observer-polyfill@1.5.1 + scroll-into-view-if-needed: registry.npmmirror.com/scroll-into-view-if-needed@2.2.31 + utility-types: registry.npmmirror.com/utility-types@3.10.0 + dev: false + + registry.npmmirror.com/@esbuild/android-arm64@0.19.8: + resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz} + name: '@esbuild/android-arm64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/android-arm@0.19.8: + resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz} + name: '@esbuild/android-arm' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/android-x64@0.19.8: + resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz} + name: '@esbuild/android-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/darwin-arm64@0.19.8: + resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz} + name: '@esbuild/darwin-arm64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/darwin-x64@0.19.8: + resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz} + name: '@esbuild/darwin-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/freebsd-arm64@0.19.8: + resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz} + name: '@esbuild/freebsd-arm64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/freebsd-x64@0.19.8: + resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz} + name: '@esbuild/freebsd-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-arm64@0.19.8: + resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz} + name: '@esbuild/linux-arm64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-arm@0.19.8: + resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz} + name: '@esbuild/linux-arm' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-ia32@0.19.8: + resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz} + name: '@esbuild/linux-ia32' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-loong64@0.19.8: + resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz} + name: '@esbuild/linux-loong64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-mips64el@0.19.8: + resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz} + name: '@esbuild/linux-mips64el' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-ppc64@0.19.8: + resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz} + name: '@esbuild/linux-ppc64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-riscv64@0.19.8: + resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz} + name: '@esbuild/linux-riscv64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-s390x@0.19.8: + resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz} + name: '@esbuild/linux-s390x' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/linux-x64@0.19.8: + resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz} + name: '@esbuild/linux-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/netbsd-x64@0.19.8: + resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz} + name: '@esbuild/netbsd-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/openbsd-x64@0.19.8: + resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz} + name: '@esbuild/openbsd-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/sunos-x64@0.19.8: + resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz} + name: '@esbuild/sunos-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/win32-arm64@0.19.8: + resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz} + name: '@esbuild/win32-arm64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/win32-ia32@0.19.8: + resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz} + name: '@esbuild/win32-ia32' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@esbuild/win32-x64@0.19.8: + resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz} + name: '@esbuild/win32-x64' + version: 0.19.8 + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz} + id: registry.npmmirror.com/@eslint-community/eslint-utils/4.4.0 + name: '@eslint-community/eslint-utils' + version: 4.4.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: registry.npmmirror.com/eslint@8.53.0 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + dev: true + + registry.npmmirror.com/@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz} + name: '@eslint-community/regexpp' + version: 4.10.0 + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + registry.npmmirror.com/@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz} + name: '@eslint/eslintrc' + version: 2.1.3 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: registry.npmmirror.com/ajv@6.12.6 + debug: registry.npmmirror.com/debug@4.3.4 + espree: registry.npmmirror.com/espree@9.6.1 + globals: registry.npmmirror.com/globals@13.23.0 + ignore: registry.npmmirror.com/ignore@5.3.0 + import-fresh: registry.npmmirror.com/import-fresh@3.3.0 + js-yaml: registry.npmmirror.com/js-yaml@4.1.0 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + strip-json-comments: registry.npmmirror.com/strip-json-comments@3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@eslint/js@8.53.0: + resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@eslint/js/-/js-8.53.0.tgz} + name: '@eslint/js' + version: 8.53.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + registry.npmmirror.com/@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz} + name: '@humanwhocodes/config-array' + version: 0.11.13 + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': registry.npmmirror.com/@humanwhocodes/object-schema@2.0.1 + debug: registry.npmmirror.com/debug@4.3.4 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz} + name: '@humanwhocodes/module-importer' + version: 1.0.1 + engines: {node: '>=12.22'} + dev: true + + registry.npmmirror.com/@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz} + name: '@humanwhocodes/object-schema' + version: 2.0.1 + dev: true + + registry.npmmirror.com/@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz} + name: '@jridgewell/gen-mapping' + version: 0.3.3 + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': registry.npmmirror.com/@jridgewell/set-array@1.1.2 + '@jridgewell/sourcemap-codec': registry.npmmirror.com/@jridgewell/sourcemap-codec@1.4.15 + '@jridgewell/trace-mapping': registry.npmmirror.com/@jridgewell/trace-mapping@0.3.20 + dev: true + + registry.npmmirror.com/@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz} + name: '@jridgewell/resolve-uri' + version: 3.1.1 + engines: {node: '>=6.0.0'} + dev: true + + registry.npmmirror.com/@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.1.2.tgz} + name: '@jridgewell/set-array' + version: 1.1.2 + engines: {node: '>=6.0.0'} + dev: true + + registry.npmmirror.com/@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz} + name: '@jridgewell/sourcemap-codec' + version: 1.4.15 + dev: true + + registry.npmmirror.com/@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz} + name: '@jridgewell/trace-mapping' + version: 0.3.20 + dependencies: + '@jridgewell/resolve-uri': registry.npmmirror.com/@jridgewell/resolve-uri@3.1.1 + '@jridgewell/sourcemap-codec': registry.npmmirror.com/@jridgewell/sourcemap-codec@1.4.15 + dev: true + + registry.npmmirror.com/@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz} + name: '@nodelib/fs.scandir' + version: 2.1.5 + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': registry.npmmirror.com/@nodelib/fs.stat@2.0.5 + run-parallel: registry.npmmirror.com/run-parallel@1.2.0 + dev: true + + registry.npmmirror.com/@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz} + name: '@nodelib/fs.stat' + version: 2.0.5 + engines: {node: '>= 8'} + dev: true + + registry.npmmirror.com/@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz} + name: '@nodelib/fs.walk' + version: 1.2.8 + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': registry.npmmirror.com/@nodelib/fs.scandir@2.1.5 + fastq: registry.npmmirror.com/fastq@1.15.0 + dev: true + + registry.npmmirror.com/@remix-run/router@1.13.0: + resolution: {integrity: sha512-5dMOnVnefRsl4uRnAdoWjtVTdh8e6aZqgM4puy9nmEADH72ck+uXwzpJLEKE9Q6F8ZljNewLgmTfkxUrBdv4WA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@remix-run/router/-/router-1.13.0.tgz} + name: '@remix-run/router' + version: 1.13.0 + engines: {node: '>=14.0.0'} + dev: false + + registry.npmmirror.com/@rollup/pluginutils@5.1.0: + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz} + name: '@rollup/pluginutils' + version: 5.1.0 + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': registry.npmmirror.com/@types/estree@1.0.5 + estree-walker: registry.npmmirror.com/estree-walker@2.0.2 + picomatch: registry.npmmirror.com/picomatch@2.3.1 + dev: true + + registry.npmmirror.com/@rollup/rollup-android-arm-eabi@4.6.1: + resolution: {integrity: sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz} + name: '@rollup/rollup-android-arm-eabi' + version: 4.6.1 + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-android-arm64@4.6.1: + resolution: {integrity: sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz} + name: '@rollup/rollup-android-arm64' + version: 4.6.1 + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-darwin-arm64@4.6.1: + resolution: {integrity: sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz} + name: '@rollup/rollup-darwin-arm64' + version: 4.6.1 + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-darwin-x64@4.6.1: + resolution: {integrity: sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz} + name: '@rollup/rollup-darwin-x64' + version: 4.6.1 + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf@4.6.1: + resolution: {integrity: sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz} + name: '@rollup/rollup-linux-arm-gnueabihf' + version: 4.6.1 + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu@4.6.1: + resolution: {integrity: sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz} + name: '@rollup/rollup-linux-arm64-gnu' + version: 4.6.1 + cpu: [arm64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-linux-arm64-musl@4.6.1: + resolution: {integrity: sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz} + name: '@rollup/rollup-linux-arm64-musl' + version: 4.6.1 + cpu: [arm64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-linux-x64-gnu@4.6.1: + resolution: {integrity: sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz} + name: '@rollup/rollup-linux-x64-gnu' + version: 4.6.1 + cpu: [x64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-linux-x64-musl@4.6.1: + resolution: {integrity: sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz} + name: '@rollup/rollup-linux-x64-musl' + version: 4.6.1 + cpu: [x64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc@4.6.1: + resolution: {integrity: sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz} + name: '@rollup/rollup-win32-arm64-msvc' + version: 4.6.1 + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc@4.6.1: + resolution: {integrity: sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz} + name: '@rollup/rollup-win32-ia32-msvc' + version: 4.6.1 + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@rollup/rollup-win32-x64-msvc@4.6.1: + resolution: {integrity: sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz} + name: '@rollup/rollup-win32-x64-msvc' + version: 4.6.1 + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + registry.npmmirror.com/@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-add-jsx-attribute/8.0.0 + name: '@svgr/babel-plugin-add-jsx-attribute' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-attribute/8.0.0 + name: '@svgr/babel-plugin-remove-jsx-attribute' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-empty-expression/8.0.0 + name: '@svgr/babel-plugin-remove-jsx-empty-expression' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-replace-jsx-attribute-value/8.0.0 + name: '@svgr/babel-plugin-replace-jsx-attribute-value' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-svg-dynamic-title/8.0.0 + name: '@svgr/babel-plugin-svg-dynamic-title' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-svg-em-dimensions/8.0.0 + name: '@svgr/babel-plugin-svg-em-dimensions' + version: 8.0.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.23.5): + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-transform-react-native-svg/8.1.0 + name: '@svgr/babel-plugin-transform-react-native-svg' + version: 8.1.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.23.5): + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz} + id: registry.npmmirror.com/@svgr/babel-plugin-transform-svg-component/8.0.0 + name: '@svgr/babel-plugin-transform-svg-component' + version: 8.0.0 + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + dev: true + + registry.npmmirror.com/@svgr/babel-preset@8.1.0(@babel/core@7.23.5): + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/babel-preset/-/babel-preset-8.1.0.tgz} + id: registry.npmmirror.com/@svgr/babel-preset/8.1.0 + name: '@svgr/babel-preset' + version: 8.1.0 + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@svgr/babel-plugin-add-jsx-attribute': registry.npmmirror.com/@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-remove-jsx-attribute': registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': registry.npmmirror.com/@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-svg-dynamic-title': registry.npmmirror.com/@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-svg-em-dimensions': registry.npmmirror.com/@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.23.5) + '@svgr/babel-plugin-transform-react-native-svg': registry.npmmirror.com/@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.23.5) + '@svgr/babel-plugin-transform-svg-component': registry.npmmirror.com/@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.23.5) + dev: true + + registry.npmmirror.com/@svgr/core@8.1.0(typescript@5.2.2): + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/core/-/core-8.1.0.tgz} + id: registry.npmmirror.com/@svgr/core/8.1.0 + name: '@svgr/core' + version: 8.1.0 + engines: {node: '>=14'} + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@svgr/babel-preset': registry.npmmirror.com/@svgr/babel-preset@8.1.0(@babel/core@7.23.5) + camelcase: registry.npmmirror.com/camelcase@6.3.0 + cosmiconfig: registry.npmmirror.com/cosmiconfig@8.3.6(typescript@5.2.2) + snake-case: registry.npmmirror.com/snake-case@3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + registry.npmmirror.com/@svgr/hast-util-to-babel-ast@8.0.0: + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz} + name: '@svgr/hast-util-to-babel-ast' + version: 8.0.0 + engines: {node: '>=14'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + entities: registry.npmmirror.com/entities@4.5.0 + dev: true + + registry.npmmirror.com/@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0): + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz} + id: registry.npmmirror.com/@svgr/plugin-jsx/8.1.0 + name: '@svgr/plugin-jsx' + version: 8.1.0 + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@svgr/babel-preset': registry.npmmirror.com/@svgr/babel-preset@8.1.0(@babel/core@7.23.5) + '@svgr/core': registry.npmmirror.com/@svgr/core@8.1.0(typescript@5.2.2) + '@svgr/hast-util-to-babel-ast': registry.npmmirror.com/@svgr/hast-util-to-babel-ast@8.0.0 + svg-parser: registry.npmmirror.com/svg-parser@2.0.4 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz} + name: '@types/babel__core' + version: 7.20.5 + dependencies: + '@babel/parser': registry.npmmirror.com/@babel/parser@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + '@types/babel__generator': registry.npmmirror.com/@types/babel__generator@7.6.7 + '@types/babel__template': registry.npmmirror.com/@types/babel__template@7.4.4 + '@types/babel__traverse': registry.npmmirror.com/@types/babel__traverse@7.20.4 + dev: true + + registry.npmmirror.com/@types/babel__generator@7.6.7: + resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/babel__generator/-/babel__generator-7.6.7.tgz} + name: '@types/babel__generator' + version: 7.6.7 + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/babel__template/-/babel__template-7.4.4.tgz} + name: '@types/babel__template' + version: 7.4.4 + dependencies: + '@babel/parser': registry.npmmirror.com/@babel/parser@7.23.5 + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@types/babel__traverse@7.20.4: + resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz} + name: '@types/babel__traverse' + version: 7.20.4 + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.5 + dev: true + + registry.npmmirror.com/@types/echarts@4.9.22: + resolution: {integrity: sha512-7Fo6XdWpoi8jxkwP7BARUOM7riq8bMhmsCtSG8gzUcJmFhLo387tihoBYS/y5j7jl3PENT5RxeWZdN9RiwO7HQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/echarts/-/echarts-4.9.22.tgz} + name: '@types/echarts' + version: 4.9.22 + dependencies: + '@types/zrender': registry.npmmirror.com/@types/zrender@4.0.6 + dev: true + + registry.npmmirror.com/@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/estree/-/estree-1.0.5.tgz} + name: '@types/estree' + version: 1.0.5 + dev: true + + registry.npmmirror.com/@types/js-cookie@3.0.6: + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.6.tgz} + name: '@types/js-cookie' + version: 3.0.6 + dev: true + + registry.npmmirror.com/@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz} + name: '@types/json-schema' + version: 7.0.15 + dev: true + + registry.npmmirror.com/@types/prop-types@15.7.11: + resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.11.tgz} + name: '@types/prop-types' + version: 15.7.11 + dev: true + + registry.npmmirror.com/@types/react-dom@18.2.15: + resolution: {integrity: sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.2.15.tgz} + name: '@types/react-dom' + version: 18.2.15 + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.2.37 + dev: true + + registry.npmmirror.com/@types/react@18.2.37: + resolution: {integrity: sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react/-/react-18.2.37.tgz} + name: '@types/react' + version: 18.2.37 + dependencies: + '@types/prop-types': registry.npmmirror.com/@types/prop-types@15.7.11 + '@types/scheduler': registry.npmmirror.com/@types/scheduler@0.16.8 + csstype: registry.npmmirror.com/csstype@3.1.2 + dev: true + + registry.npmmirror.com/@types/scheduler@0.16.8: + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.8.tgz} + name: '@types/scheduler' + version: 0.16.8 + dev: true + + registry.npmmirror.com/@types/semver@7.5.6: + resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/semver/-/semver-7.5.6.tgz} + name: '@types/semver' + version: 7.5.6 + dev: true + + registry.npmmirror.com/@types/zrender@4.0.6: + resolution: {integrity: sha512-1jZ9bJn2BsfmYFPBHtl5o3uV+ILejAtGrDcYSpT4qaVKEI/0YY+arw3XHU04Ebd8Nca3SQ7uNcLaqiL+tTFVMg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/zrender/-/zrender-4.0.6.tgz} + name: '@types/zrender' + version: 4.0.6 + dev: true + + registry.npmmirror.com/@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0)(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/eslint-plugin/6.10.0 + name: '@typescript-eslint/eslint-plugin' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': registry.npmmirror.com/@eslint-community/regexpp@4.10.0 + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@6.10.0 + '@typescript-eslint/type-utils': registry.npmmirror.com/@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.10.0 + debug: registry.npmmirror.com/debug@4.3.4 + eslint: registry.npmmirror.com/eslint@8.53.0 + graphemer: registry.npmmirror.com/graphemer@1.4.0 + ignore: registry.npmmirror.com/ignore@5.3.0 + natural-compare: registry.npmmirror.com/natural-compare@1.4.0 + semver: registry.npmmirror.com/semver@7.5.4 + ts-api-utils: registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.2.2) + typescript: registry.npmmirror.com/typescript@5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-6.10.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/parser/6.10.0 + name: '@typescript-eslint/parser' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@6.10.0 + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.10.0 + '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.10.0 + debug: registry.npmmirror.com/debug@4.3.4 + eslint: registry.npmmirror.com/eslint@8.53.0 + typescript: registry.npmmirror.com/typescript@5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/scope-manager@6.10.0: + resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz} + name: '@typescript-eslint/scope-manager' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.10.0 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.10.0 + dev: true + + registry.npmmirror.com/@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/type-utils/6.10.0 + name: '@typescript-eslint/type-utils' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2) + '@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2) + debug: registry.npmmirror.com/debug@4.3.4 + eslint: registry.npmmirror.com/eslint@8.53.0 + ts-api-utils: registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.2.2) + typescript: registry.npmmirror.com/typescript@5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/types@6.10.0: + resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/types/-/types-6.10.0.tgz} + name: '@typescript-eslint/types' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + registry.npmmirror.com/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2): + resolution: {integrity: sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/typescript-estree/6.10.0 + name: '@typescript-eslint/typescript-estree' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.10.0 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.10.0 + debug: registry.npmmirror.com/debug@4.3.4 + globby: registry.npmmirror.com/globby@11.1.0 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + semver: registry.npmmirror.com/semver@7.5.4 + ts-api-utils: registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.2.2) + typescript: registry.npmmirror.com/typescript@5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-6.10.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/utils/6.10.0 + name: '@typescript-eslint/utils' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': registry.npmmirror.com/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0) + '@types/json-schema': registry.npmmirror.com/@types/json-schema@7.0.15 + '@types/semver': registry.npmmirror.com/@types/semver@7.5.6 + '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@6.10.0 + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.10.0 + '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2) + eslint: registry.npmmirror.com/eslint@8.53.0 + semver: registry.npmmirror.com/semver@7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + registry.npmmirror.com/@typescript-eslint/visitor-keys@6.10.0: + resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz} + name: '@typescript-eslint/visitor-keys' + version: 6.10.0 + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.10.0 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + dev: true + + registry.npmmirror.com/@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz} + name: '@ungap/structured-clone' + version: 1.2.0 + dev: true + + registry.npmmirror.com/@vitejs/plugin-react@4.2.0(vite@5.0.0): + resolution: {integrity: sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz} + id: registry.npmmirror.com/@vitejs/plugin-react/4.2.0 + name: '@vitejs/plugin-react' + version: 4.2.0 + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + dependencies: + '@babel/core': registry.npmmirror.com/@babel/core@7.23.5 + '@babel/plugin-transform-react-jsx-self': registry.npmmirror.com/@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-react-jsx-source': registry.npmmirror.com/@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.5) + '@types/babel__core': registry.npmmirror.com/@types/babel__core@7.20.5 + react-refresh: registry.npmmirror.com/react-refresh@0.14.0 + vite: registry.npmmirror.com/vite@5.0.0(sass@1.69.5) + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/acorn-jsx@5.3.2(acorn@8.11.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz} + id: registry.npmmirror.com/acorn-jsx/5.3.2 + name: acorn-jsx + version: 5.3.2 + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: registry.npmmirror.com/acorn@8.11.2 + dev: true + + registry.npmmirror.com/acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn/-/acorn-8.11.2.tgz} + name: acorn + version: 8.11.2 + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + registry.npmmirror.com/ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz} + name: ajv + version: 6.12.6 + dependencies: + fast-deep-equal: registry.npmmirror.com/fast-deep-equal@3.1.3 + fast-json-stable-stringify: registry.npmmirror.com/fast-json-stable-stringify@2.1.0 + json-schema-traverse: registry.npmmirror.com/json-schema-traverse@0.4.1 + uri-js: registry.npmmirror.com/uri-js@4.4.1 + dev: true + + registry.npmmirror.com/ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz} + name: ansi-regex + version: 5.0.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz} + name: ansi-styles + version: 3.2.1 + engines: {node: '>=4'} + dependencies: + color-convert: registry.npmmirror.com/color-convert@1.9.3 + dev: true + + registry.npmmirror.com/ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz} + name: ansi-styles + version: 4.3.0 + engines: {node: '>=8'} + dependencies: + color-convert: registry.npmmirror.com/color-convert@2.0.1 + dev: true + + registry.npmmirror.com/anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz} + name: anymatch + version: 3.1.3 + engines: {node: '>= 8'} + dependencies: + normalize-path: registry.npmmirror.com/normalize-path@3.0.0 + picomatch: registry.npmmirror.com/picomatch@2.3.1 + + registry.npmmirror.com/argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz} + name: argparse + version: 2.0.1 + dev: true + + registry.npmmirror.com/array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz} + name: array-union + version: 2.1.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/async-validator@3.5.2: + resolution: {integrity: sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/async-validator/-/async-validator-3.5.2.tgz} + name: async-validator + version: 3.5.2 + dev: false + + registry.npmmirror.com/balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz} + name: balanced-match + version: 1.0.2 + + registry.npmmirror.com/bezier-easing@2.1.0: + resolution: {integrity: sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/bezier-easing/-/bezier-easing-2.1.0.tgz} + name: bezier-easing + version: 2.1.0 + dev: false + + registry.npmmirror.com/binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz} + name: binary-extensions + version: 2.2.0 + engines: {node: '>=8'} + + registry.npmmirror.com/brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz} + name: brace-expansion + version: 1.1.11 + dependencies: + balanced-match: registry.npmmirror.com/balanced-match@1.0.2 + concat-map: registry.npmmirror.com/concat-map@0.0.1 + + registry.npmmirror.com/braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz} + name: braces + version: 3.0.2 + engines: {node: '>=8'} + dependencies: + fill-range: registry.npmmirror.com/fill-range@7.0.1 + + registry.npmmirror.com/browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/browserslist/-/browserslist-4.22.1.tgz} + name: browserslist + version: 4.22.1 + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: registry.npmmirror.com/caniuse-lite@1.0.30001565 + electron-to-chromium: registry.npmmirror.com/electron-to-chromium@1.4.597 + node-releases: registry.npmmirror.com/node-releases@2.0.13 + update-browserslist-db: registry.npmmirror.com/update-browserslist-db@1.0.13(browserslist@4.22.1) + dev: true + + registry.npmmirror.com/callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz} + name: callsites + version: 3.1.0 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz} + name: camelcase + version: 6.3.0 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/caniuse-lite@1.0.30001565: + resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz} + name: caniuse-lite + version: 1.0.30001565 + dev: true + + registry.npmmirror.com/chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz} + name: chalk + version: 2.4.2 + engines: {node: '>=4'} + dependencies: + ansi-styles: registry.npmmirror.com/ansi-styles@3.2.1 + escape-string-regexp: registry.npmmirror.com/escape-string-regexp@1.0.5 + supports-color: registry.npmmirror.com/supports-color@5.5.0 + dev: true + + registry.npmmirror.com/chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz} + name: chalk + version: 4.1.2 + engines: {node: '>=10'} + dependencies: + ansi-styles: registry.npmmirror.com/ansi-styles@4.3.0 + supports-color: registry.npmmirror.com/supports-color@7.2.0 + dev: true + + registry.npmmirror.com/chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz} + name: chokidar + version: 3.5.3 + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: registry.npmmirror.com/anymatch@3.1.3 + braces: registry.npmmirror.com/braces@3.0.2 + glob-parent: registry.npmmirror.com/glob-parent@5.1.2 + is-binary-path: registry.npmmirror.com/is-binary-path@2.1.0 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + normalize-path: registry.npmmirror.com/normalize-path@3.0.0 + readdirp: registry.npmmirror.com/readdirp@3.6.0 + optionalDependencies: + fsevents: registry.npmmirror.com/fsevents@2.3.3 + + registry.npmmirror.com/classnames@2.3.2: + resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/classnames/-/classnames-2.3.2.tgz} + name: classnames + version: 2.3.2 + dev: false + + registry.npmmirror.com/clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/clsx/-/clsx-1.2.1.tgz} + name: clsx + version: 1.2.1 + engines: {node: '>=6'} + dev: false + + registry.npmmirror.com/color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz} + name: color-convert + version: 1.9.3 + dependencies: + color-name: registry.npmmirror.com/color-name@1.1.3 + dev: true + + registry.npmmirror.com/color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz} + name: color-convert + version: 2.0.1 + engines: {node: '>=7.0.0'} + dependencies: + color-name: registry.npmmirror.com/color-name@1.1.4 + dev: true + + registry.npmmirror.com/color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz} + name: color-name + version: 1.1.3 + dev: true + + registry.npmmirror.com/color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz} + name: color-name + version: 1.1.4 + dev: true + + registry.npmmirror.com/compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz} + name: compute-scroll-into-view + version: 1.0.20 + dev: false + + registry.npmmirror.com/concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz} + name: concat-map + version: 0.0.1 + + registry.npmmirror.com/convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz} + name: convert-source-map + version: 2.0.0 + dev: true + + registry.npmmirror.com/copy-text-to-clipboard@2.2.0: + resolution: {integrity: sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz} + name: copy-text-to-clipboard + version: 2.2.0 + engines: {node: '>=6'} + dev: false + + registry.npmmirror.com/cosmiconfig@8.3.6(typescript@5.2.2): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz} + id: registry.npmmirror.com/cosmiconfig/8.3.6 + name: cosmiconfig + version: 8.3.6 + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: registry.npmmirror.com/import-fresh@3.3.0 + js-yaml: registry.npmmirror.com/js-yaml@4.1.0 + parse-json: registry.npmmirror.com/parse-json@5.2.0 + path-type: registry.npmmirror.com/path-type@4.0.0 + typescript: registry.npmmirror.com/typescript@5.2.2 + dev: true + + registry.npmmirror.com/cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz} + name: cross-spawn + version: 7.0.3 + engines: {node: '>= 8'} + dependencies: + path-key: registry.npmmirror.com/path-key@3.1.1 + shebang-command: registry.npmmirror.com/shebang-command@2.0.0 + which: registry.npmmirror.com/which@2.0.2 + dev: true + + registry.npmmirror.com/csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz} + name: csstype + version: 3.1.2 + dev: true + + registry.npmmirror.com/date-fns-tz@1.3.8(date-fns@2.30.0): + resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-1.3.8.tgz} + id: registry.npmmirror.com/date-fns-tz/1.3.8 + name: date-fns-tz + version: 1.3.8 + peerDependencies: + date-fns: '>=2.0.0' + dependencies: + date-fns: registry.npmmirror.com/date-fns@2.30.0 + dev: false + + registry.npmmirror.com/date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/date-fns/-/date-fns-2.30.0.tgz} + name: date-fns + version: 2.30.0 + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.5 + dev: false + + registry.npmmirror.com/debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz} + name: debug + version: 4.3.4 + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: registry.npmmirror.com/ms@2.1.2 + dev: true + + registry.npmmirror.com/deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz} + name: deep-is + version: 0.1.4 + dev: true + + registry.npmmirror.com/dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz} + name: dir-glob + version: 3.0.1 + engines: {node: '>=8'} + dependencies: + path-type: registry.npmmirror.com/path-type@4.0.0 + dev: true + + registry.npmmirror.com/doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz} + name: doctrine + version: 3.0.0 + engines: {node: '>=6.0.0'} + dependencies: + esutils: registry.npmmirror.com/esutils@2.0.3 + dev: true + + registry.npmmirror.com/dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz} + name: dot-case + version: 3.0.4 + dependencies: + no-case: registry.npmmirror.com/no-case@3.0.4 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: true + + registry.npmmirror.com/echarts@5.4.3: + resolution: {integrity: sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz} + name: echarts + version: 5.4.3 + dependencies: + tslib: registry.npmmirror.com/tslib@2.3.0 + zrender: registry.npmmirror.com/zrender@5.4.4 + dev: false + + registry.npmmirror.com/electron-to-chromium@1.4.597: + resolution: {integrity: sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.597.tgz} + name: electron-to-chromium + version: 1.4.597 + dev: true + + registry.npmmirror.com/entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz} + name: entities + version: 4.5.0 + engines: {node: '>=0.12'} + dev: true + + registry.npmmirror.com/error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz} + name: error-ex + version: 1.3.2 + dependencies: + is-arrayish: registry.npmmirror.com/is-arrayish@0.2.1 + dev: true + + registry.npmmirror.com/esbuild@0.19.8: + resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild/-/esbuild-0.19.8.tgz} + name: esbuild + version: 0.19.8 + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': registry.npmmirror.com/@esbuild/android-arm@0.19.8 + '@esbuild/android-arm64': registry.npmmirror.com/@esbuild/android-arm64@0.19.8 + '@esbuild/android-x64': registry.npmmirror.com/@esbuild/android-x64@0.19.8 + '@esbuild/darwin-arm64': registry.npmmirror.com/@esbuild/darwin-arm64@0.19.8 + '@esbuild/darwin-x64': registry.npmmirror.com/@esbuild/darwin-x64@0.19.8 + '@esbuild/freebsd-arm64': registry.npmmirror.com/@esbuild/freebsd-arm64@0.19.8 + '@esbuild/freebsd-x64': registry.npmmirror.com/@esbuild/freebsd-x64@0.19.8 + '@esbuild/linux-arm': registry.npmmirror.com/@esbuild/linux-arm@0.19.8 + '@esbuild/linux-arm64': registry.npmmirror.com/@esbuild/linux-arm64@0.19.8 + '@esbuild/linux-ia32': registry.npmmirror.com/@esbuild/linux-ia32@0.19.8 + '@esbuild/linux-loong64': registry.npmmirror.com/@esbuild/linux-loong64@0.19.8 + '@esbuild/linux-mips64el': registry.npmmirror.com/@esbuild/linux-mips64el@0.19.8 + '@esbuild/linux-ppc64': registry.npmmirror.com/@esbuild/linux-ppc64@0.19.8 + '@esbuild/linux-riscv64': registry.npmmirror.com/@esbuild/linux-riscv64@0.19.8 + '@esbuild/linux-s390x': registry.npmmirror.com/@esbuild/linux-s390x@0.19.8 + '@esbuild/linux-x64': registry.npmmirror.com/@esbuild/linux-x64@0.19.8 + '@esbuild/netbsd-x64': registry.npmmirror.com/@esbuild/netbsd-x64@0.19.8 + '@esbuild/openbsd-x64': registry.npmmirror.com/@esbuild/openbsd-x64@0.19.8 + '@esbuild/sunos-x64': registry.npmmirror.com/@esbuild/sunos-x64@0.19.8 + '@esbuild/win32-arm64': registry.npmmirror.com/@esbuild/win32-arm64@0.19.8 + '@esbuild/win32-ia32': registry.npmmirror.com/@esbuild/win32-ia32@0.19.8 + '@esbuild/win32-x64': registry.npmmirror.com/@esbuild/win32-x64@0.19.8 + dev: true + + registry.npmmirror.com/escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz} + name: escalade + version: 3.1.1 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz} + name: escape-string-regexp + version: 1.0.5 + engines: {node: '>=0.8.0'} + dev: true + + registry.npmmirror.com/escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz} + name: escape-string-regexp + version: 4.0.0 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/eslint-plugin-react-hooks@4.6.0(eslint@8.53.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz} + id: registry.npmmirror.com/eslint-plugin-react-hooks/4.6.0 + name: eslint-plugin-react-hooks + version: 4.6.0 + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: registry.npmmirror.com/eslint@8.53.0 + dev: true + + registry.npmmirror.com/eslint-plugin-react-refresh@0.4.4(eslint@8.53.0): + resolution: {integrity: sha512-eD83+65e8YPVg6603Om2iCIwcQJf/y7++MWm4tACtEswFLYMwxwVWAfwN+e19f5Ad/FOyyNg9Dfi5lXhH3Y3rA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.4.tgz} + id: registry.npmmirror.com/eslint-plugin-react-refresh/0.4.4 + name: eslint-plugin-react-refresh + version: 0.4.4 + peerDependencies: + eslint: '>=7' + dependencies: + eslint: registry.npmmirror.com/eslint@8.53.0 + dev: true + + registry.npmmirror.com/eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz} + name: eslint-scope + version: 7.2.2 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: registry.npmmirror.com/esrecurse@4.3.0 + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz} + name: eslint-visitor-keys + version: 3.4.3 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + registry.npmmirror.com/eslint@8.53.0: + resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint/-/eslint-8.53.0.tgz} + name: eslint + version: 8.53.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': registry.npmmirror.com/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0) + '@eslint-community/regexpp': registry.npmmirror.com/@eslint-community/regexpp@4.10.0 + '@eslint/eslintrc': registry.npmmirror.com/@eslint/eslintrc@2.1.3 + '@eslint/js': registry.npmmirror.com/@eslint/js@8.53.0 + '@humanwhocodes/config-array': registry.npmmirror.com/@humanwhocodes/config-array@0.11.13 + '@humanwhocodes/module-importer': registry.npmmirror.com/@humanwhocodes/module-importer@1.0.1 + '@nodelib/fs.walk': registry.npmmirror.com/@nodelib/fs.walk@1.2.8 + '@ungap/structured-clone': registry.npmmirror.com/@ungap/structured-clone@1.2.0 + ajv: registry.npmmirror.com/ajv@6.12.6 + chalk: registry.npmmirror.com/chalk@4.1.2 + cross-spawn: registry.npmmirror.com/cross-spawn@7.0.3 + debug: registry.npmmirror.com/debug@4.3.4 + doctrine: registry.npmmirror.com/doctrine@3.0.0 + escape-string-regexp: registry.npmmirror.com/escape-string-regexp@4.0.0 + eslint-scope: registry.npmmirror.com/eslint-scope@7.2.2 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + espree: registry.npmmirror.com/espree@9.6.1 + esquery: registry.npmmirror.com/esquery@1.5.0 + esutils: registry.npmmirror.com/esutils@2.0.3 + fast-deep-equal: registry.npmmirror.com/fast-deep-equal@3.1.3 + file-entry-cache: registry.npmmirror.com/file-entry-cache@6.0.1 + find-up: registry.npmmirror.com/find-up@5.0.0 + glob-parent: registry.npmmirror.com/glob-parent@6.0.2 + globals: registry.npmmirror.com/globals@13.23.0 + graphemer: registry.npmmirror.com/graphemer@1.4.0 + ignore: registry.npmmirror.com/ignore@5.3.0 + imurmurhash: registry.npmmirror.com/imurmurhash@0.1.4 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + is-path-inside: registry.npmmirror.com/is-path-inside@3.0.3 + js-yaml: registry.npmmirror.com/js-yaml@4.1.0 + json-stable-stringify-without-jsonify: registry.npmmirror.com/json-stable-stringify-without-jsonify@1.0.1 + levn: registry.npmmirror.com/levn@0.4.1 + lodash.merge: registry.npmmirror.com/lodash.merge@4.6.2 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + natural-compare: registry.npmmirror.com/natural-compare@1.4.0 + optionator: registry.npmmirror.com/optionator@0.9.3 + strip-ansi: registry.npmmirror.com/strip-ansi@6.0.1 + text-table: registry.npmmirror.com/text-table@0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz} + name: espree + version: 9.6.1 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: registry.npmmirror.com/acorn@8.11.2 + acorn-jsx: registry.npmmirror.com/acorn-jsx@5.3.2(acorn@8.11.2) + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + dev: true + + registry.npmmirror.com/esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz} + name: esquery + version: 1.5.0 + engines: {node: '>=0.10'} + dependencies: + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz} + name: esrecurse + version: 4.3.0 + engines: {node: '>=4.0'} + dependencies: + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz} + name: estraverse + version: 5.3.0 + engines: {node: '>=4.0'} + dev: true + + registry.npmmirror.com/estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz} + name: estree-walker + version: 2.0.2 + dev: true + + registry.npmmirror.com/esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz} + name: esutils + version: 2.0.3 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz} + name: fast-deep-equal + version: 3.1.3 + dev: true + + registry.npmmirror.com/fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz} + name: fast-glob + version: 3.3.2 + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': registry.npmmirror.com/@nodelib/fs.stat@2.0.5 + '@nodelib/fs.walk': registry.npmmirror.com/@nodelib/fs.walk@1.2.8 + glob-parent: registry.npmmirror.com/glob-parent@5.1.2 + merge2: registry.npmmirror.com/merge2@1.4.1 + micromatch: registry.npmmirror.com/micromatch@4.0.5 + dev: true + + registry.npmmirror.com/fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz} + name: fast-json-stable-stringify + version: 2.1.0 + dev: true + + registry.npmmirror.com/fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz} + name: fast-levenshtein + version: 2.0.6 + dev: true + + registry.npmmirror.com/fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz} + name: fastq + version: 1.15.0 + dependencies: + reusify: registry.npmmirror.com/reusify@1.0.4 + dev: true + + registry.npmmirror.com/file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz} + name: file-entry-cache + version: 6.0.1 + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: registry.npmmirror.com/flat-cache@3.2.0 + dev: true + + registry.npmmirror.com/fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz} + name: fill-range + version: 7.0.1 + engines: {node: '>=8'} + dependencies: + to-regex-range: registry.npmmirror.com/to-regex-range@5.0.1 + + registry.npmmirror.com/find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz} + name: find-up + version: 5.0.0 + engines: {node: '>=10'} + dependencies: + locate-path: registry.npmmirror.com/locate-path@6.0.0 + path-exists: registry.npmmirror.com/path-exists@4.0.0 + dev: true + + registry.npmmirror.com/flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz} + name: flat-cache + version: 3.2.0 + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: registry.npmmirror.com/flatted@3.2.9 + keyv: registry.npmmirror.com/keyv@4.5.4 + rimraf: registry.npmmirror.com/rimraf@3.0.2 + dev: true + + registry.npmmirror.com/flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/flatted/-/flatted-3.2.9.tgz} + name: flatted + version: 3.2.9 + dev: true + + registry.npmmirror.com/fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz} + name: fs.realpath + version: 1.0.0 + + registry.npmmirror.com/fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz} + name: fsevents + version: 2.3.3 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + registry.npmmirror.com/gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz} + name: gensync + version: 1.0.0-beta.2 + engines: {node: '>=6.9.0'} + dev: true + + registry.npmmirror.com/glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz} + name: glob-parent + version: 5.1.2 + engines: {node: '>= 6'} + dependencies: + is-glob: registry.npmmirror.com/is-glob@4.0.3 + + registry.npmmirror.com/glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz} + name: glob-parent + version: 6.0.2 + engines: {node: '>=10.13.0'} + dependencies: + is-glob: registry.npmmirror.com/is-glob@4.0.3 + dev: true + + registry.npmmirror.com/glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz} + name: glob + version: 7.2.3 + dependencies: + fs.realpath: registry.npmmirror.com/fs.realpath@1.0.0 + inflight: registry.npmmirror.com/inflight@1.0.6 + inherits: registry.npmmirror.com/inherits@2.0.4 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + once: registry.npmmirror.com/once@1.4.0 + path-is-absolute: registry.npmmirror.com/path-is-absolute@1.0.1 + + registry.npmmirror.com/globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz} + name: globals + version: 11.12.0 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globals/-/globals-13.23.0.tgz} + name: globals + version: 13.23.0 + engines: {node: '>=8'} + dependencies: + type-fest: registry.npmmirror.com/type-fest@0.20.2 + dev: true + + registry.npmmirror.com/globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz} + name: globby + version: 11.1.0 + engines: {node: '>=10'} + dependencies: + array-union: registry.npmmirror.com/array-union@2.1.0 + dir-glob: registry.npmmirror.com/dir-glob@3.0.1 + fast-glob: registry.npmmirror.com/fast-glob@3.3.2 + ignore: registry.npmmirror.com/ignore@5.3.0 + merge2: registry.npmmirror.com/merge2@1.4.1 + slash: registry.npmmirror.com/slash@3.0.0 + dev: true + + registry.npmmirror.com/graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz} + name: graphemer + version: 1.4.0 + dev: true + + registry.npmmirror.com/has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz} + name: has-flag + version: 3.0.0 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz} + name: has-flag + version: 4.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ignore/-/ignore-5.3.0.tgz} + name: ignore + version: 5.3.0 + engines: {node: '>= 4'} + dev: true + + registry.npmmirror.com/immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/immutable/-/immutable-4.3.4.tgz} + name: immutable + version: 4.3.4 + + registry.npmmirror.com/import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz} + name: import-fresh + version: 3.3.0 + engines: {node: '>=6'} + dependencies: + parent-module: registry.npmmirror.com/parent-module@1.0.1 + resolve-from: registry.npmmirror.com/resolve-from@4.0.0 + dev: true + + registry.npmmirror.com/imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz} + name: imurmurhash + version: 0.1.4 + engines: {node: '>=0.8.19'} + dev: true + + registry.npmmirror.com/inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz} + name: inflight + version: 1.0.6 + dependencies: + once: registry.npmmirror.com/once@1.4.0 + wrappy: registry.npmmirror.com/wrappy@1.0.2 + + registry.npmmirror.com/inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz} + name: inherits + version: 2.0.4 + + registry.npmmirror.com/is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz} + name: is-arrayish + version: 0.2.1 + dev: true + + registry.npmmirror.com/is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz} + name: is-binary-path + version: 2.1.0 + engines: {node: '>=8'} + dependencies: + binary-extensions: registry.npmmirror.com/binary-extensions@2.2.0 + + registry.npmmirror.com/is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz} + name: is-extglob + version: 2.1.1 + engines: {node: '>=0.10.0'} + + registry.npmmirror.com/is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz} + name: is-glob + version: 4.0.3 + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: registry.npmmirror.com/is-extglob@2.1.1 + + registry.npmmirror.com/is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz} + name: is-number + version: 7.0.0 + engines: {node: '>=0.12.0'} + + registry.npmmirror.com/is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz} + name: is-path-inside + version: 3.0.3 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz} + name: isexe + version: 2.0.0 + dev: true + + registry.npmmirror.com/js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz} + name: js-cookie + version: 3.0.5 + engines: {node: '>=14'} + dev: false + + registry.npmmirror.com/js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz} + name: js-tokens + version: 4.0.0 + + registry.npmmirror.com/js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz} + name: js-yaml + version: 4.1.0 + hasBin: true + dependencies: + argparse: registry.npmmirror.com/argparse@2.0.1 + dev: true + + registry.npmmirror.com/jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz} + name: jsesc + version: 2.5.2 + engines: {node: '>=4'} + hasBin: true + dev: true + + registry.npmmirror.com/json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz} + name: json-buffer + version: 3.0.1 + dev: true + + registry.npmmirror.com/json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz} + name: json-parse-even-better-errors + version: 2.3.1 + dev: true + + registry.npmmirror.com/json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz} + name: json-schema-traverse + version: 0.4.1 + dev: true + + registry.npmmirror.com/json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz} + name: json-stable-stringify-without-jsonify + version: 1.0.1 + dev: true + + registry.npmmirror.com/json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz} + name: json5 + version: 2.2.3 + engines: {node: '>=6'} + hasBin: true + dev: true + + registry.npmmirror.com/keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz} + name: keyv + version: 4.5.4 + dependencies: + json-buffer: registry.npmmirror.com/json-buffer@3.0.1 + dev: true + + registry.npmmirror.com/levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz} + name: levn + version: 0.4.1 + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + type-check: registry.npmmirror.com/type-check@0.4.0 + dev: true + + registry.npmmirror.com/lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz} + name: lines-and-columns + version: 1.2.4 + dev: true + + registry.npmmirror.com/locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz} + name: locate-path + version: 6.0.0 + engines: {node: '>=10'} + dependencies: + p-locate: registry.npmmirror.com/p-locate@5.0.0 + dev: true + + registry.npmmirror.com/lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz} + name: lodash.merge + version: 4.6.2 + dev: true + + registry.npmmirror.com/lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz} + name: lodash + version: 4.17.21 + dev: false + + registry.npmmirror.com/loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz} + name: loose-envify + version: 1.4.0 + hasBin: true + dependencies: + js-tokens: registry.npmmirror.com/js-tokens@4.0.0 + dev: false + + registry.npmmirror.com/lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz} + name: lower-case + version: 2.0.2 + dependencies: + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: true + + registry.npmmirror.com/lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz} + name: lru-cache + version: 5.1.1 + dependencies: + yallist: registry.npmmirror.com/yallist@3.1.1 + dev: true + + registry.npmmirror.com/lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz} + name: lru-cache + version: 6.0.0 + engines: {node: '>=10'} + dependencies: + yallist: registry.npmmirror.com/yallist@4.0.0 + dev: true + + registry.npmmirror.com/memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/memoize-one/-/memoize-one-5.2.1.tgz} + name: memoize-one + version: 5.2.1 + dev: false + + registry.npmmirror.com/merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz} + name: merge2 + version: 1.4.1 + engines: {node: '>= 8'} + dev: true + + registry.npmmirror.com/micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz} + name: micromatch + version: 4.0.5 + engines: {node: '>=8.6'} + dependencies: + braces: registry.npmmirror.com/braces@3.0.2 + picomatch: registry.npmmirror.com/picomatch@2.3.1 + dev: true + + registry.npmmirror.com/minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz} + name: minimatch + version: 3.1.2 + dependencies: + brace-expansion: registry.npmmirror.com/brace-expansion@1.1.11 + + registry.npmmirror.com/moment@2.29.4: + resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz} + name: moment + version: 2.29.4 + dev: false + + registry.npmmirror.com/ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz} + name: ms + version: 2.1.2 + dev: true + + registry.npmmirror.com/nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz} + name: nanoid + version: 3.3.7 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + registry.npmmirror.com/natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz} + name: natural-compare + version: 1.4.0 + dev: true + + registry.npmmirror.com/no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz} + name: no-case + version: 3.0.4 + dependencies: + lower-case: registry.npmmirror.com/lower-case@2.0.2 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: true + + registry.npmmirror.com/node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/node-releases/-/node-releases-2.0.13.tgz} + name: node-releases + version: 2.0.13 + dev: true + + registry.npmmirror.com/normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz} + name: normalize-path + version: 3.0.0 + engines: {node: '>=0.10.0'} + + registry.npmmirror.com/object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz} + name: object-assign + version: 4.1.1 + engines: {node: '>=0.10.0'} + dev: false + + registry.npmmirror.com/once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/once/-/once-1.4.0.tgz} + name: once + version: 1.4.0 + dependencies: + wrappy: registry.npmmirror.com/wrappy@1.0.2 + + registry.npmmirror.com/optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz} + name: optionator + version: 0.9.3 + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': registry.npmmirror.com/@aashutoshrathi/word-wrap@1.2.6 + deep-is: registry.npmmirror.com/deep-is@0.1.4 + fast-levenshtein: registry.npmmirror.com/fast-levenshtein@2.0.6 + levn: registry.npmmirror.com/levn@0.4.1 + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + type-check: registry.npmmirror.com/type-check@0.4.0 + dev: true + + registry.npmmirror.com/p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz} + name: p-limit + version: 3.1.0 + engines: {node: '>=10'} + dependencies: + yocto-queue: registry.npmmirror.com/yocto-queue@0.1.0 + dev: true + + registry.npmmirror.com/p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz} + name: p-locate + version: 5.0.0 + engines: {node: '>=10'} + dependencies: + p-limit: registry.npmmirror.com/p-limit@3.1.0 + dev: true + + registry.npmmirror.com/parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz} + name: parent-module + version: 1.0.1 + engines: {node: '>=6'} + dependencies: + callsites: registry.npmmirror.com/callsites@3.1.0 + dev: true + + registry.npmmirror.com/parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz} + name: parse-json + version: 5.2.0 + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': registry.npmmirror.com/@babel/code-frame@7.23.5 + error-ex: registry.npmmirror.com/error-ex@1.3.2 + json-parse-even-better-errors: registry.npmmirror.com/json-parse-even-better-errors@2.3.1 + lines-and-columns: registry.npmmirror.com/lines-and-columns@1.2.4 + dev: true + + registry.npmmirror.com/path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz} + name: path-exists + version: 4.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz} + name: path-is-absolute + version: 1.0.1 + engines: {node: '>=0.10.0'} + + registry.npmmirror.com/path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz} + name: path-key + version: 3.1.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz} + name: path-type + version: 4.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz} + name: picocolors + version: 1.0.0 + dev: true + + registry.npmmirror.com/picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz} + name: picomatch + version: 2.3.1 + engines: {node: '>=8.6'} + + registry.npmmirror.com/postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss/-/postcss-8.4.31.tgz} + name: postcss + version: 8.4.31 + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: registry.npmmirror.com/nanoid@3.3.7 + picocolors: registry.npmmirror.com/picocolors@1.0.0 + source-map-js: registry.npmmirror.com/source-map-js@1.0.2 + dev: true + + registry.npmmirror.com/prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz} + name: prelude-ls + version: 1.2.1 + engines: {node: '>= 0.8.0'} + dev: true + + registry.npmmirror.com/prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz} + name: prop-types + version: 15.8.1 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + object-assign: registry.npmmirror.com/object-assign@4.1.1 + react-is: registry.npmmirror.com/react-is@16.13.1 + dev: false + + registry.npmmirror.com/punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz} + name: punycode + version: 2.3.1 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz} + name: queue-microtask + version: 1.2.3 + dev: true + + registry.npmmirror.com/react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz} + id: registry.npmmirror.com/react-dom/18.2.0 + name: react-dom + version: 18.2.0 + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + react: registry.npmmirror.com/react@18.2.0 + scheduler: registry.npmmirror.com/scheduler@0.23.0 + dev: false + + registry.npmmirror.com/react-draggable@4.4.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-draggable/-/react-draggable-4.4.6.tgz} + id: registry.npmmirror.com/react-draggable/4.4.6 + name: react-draggable + version: 4.4.6 + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + dependencies: + clsx: registry.npmmirror.com/clsx@1.2.1 + prop-types: registry.npmmirror.com/prop-types@15.8.1 + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + dev: false + + registry.npmmirror.com/react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz} + name: react-is + version: 16.13.1 + dev: false + + registry.npmmirror.com/react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz} + name: react-refresh + version: 0.14.0 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/react-resizable@3.0.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-resizable/-/react-resizable-3.0.5.tgz} + id: registry.npmmirror.com/react-resizable/3.0.5 + name: react-resizable + version: 3.0.5 + peerDependencies: + react: '>= 16.3' + dependencies: + prop-types: registry.npmmirror.com/prop-types@15.8.1 + react: registry.npmmirror.com/react@18.2.0 + react-draggable: registry.npmmirror.com/react-draggable@4.4.6(react-dom@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - react-dom + dev: false + + registry.npmmirror.com/react-router-dom@6.20.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CbcKjEyiSVpA6UtCHOIYLUYn/UJfwzp55va4yEfpk7JBN3GPqWfHrdLkAvNCcpXr8QoihcDMuk0dzWZxtlB/mQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.20.0.tgz} + id: registry.npmmirror.com/react-router-dom/6.20.0 + name: react-router-dom + version: 6.20.0 + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': registry.npmmirror.com/@remix-run/router@1.13.0 + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + react-router: registry.npmmirror.com/react-router@6.20.0(react@18.2.0) + dev: false + + registry.npmmirror.com/react-router@6.20.0(react@18.2.0): + resolution: {integrity: sha512-pVvzsSsgUxxtuNfTHC4IxjATs10UaAtvLGVSA1tbUE4GDaOSU1Esu2xF5nWLz7KPiMuW8BJWuPFdlGYJ7/rW0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-router/-/react-router-6.20.0.tgz} + id: registry.npmmirror.com/react-router/6.20.0 + name: react-router + version: 6.20.0 + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': registry.npmmirror.com/@remix-run/router@1.13.0 + react: registry.npmmirror.com/react@18.2.0 + dev: false + + registry.npmmirror.com/react-window@1.8.10(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-window/-/react-window-1.8.10.tgz} + id: registry.npmmirror.com/react-window/1.8.10 + name: react-window + version: 1.8.10 + engines: {node: '>8.0.0'} + peerDependencies: + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.5 + memoize-one: registry.npmmirror.com/memoize-one@5.2.1 + react: registry.npmmirror.com/react@18.2.0 + react-dom: registry.npmmirror.com/react-dom@18.2.0(react@18.2.0) + dev: false + + registry.npmmirror.com/react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react/-/react-18.2.0.tgz} + name: react + version: 18.2.0 + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + dev: false + + registry.npmmirror.com/readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz} + name: readdirp + version: 3.6.0 + engines: {node: '>=8.10.0'} + dependencies: + picomatch: registry.npmmirror.com/picomatch@2.3.1 + + registry.npmmirror.com/regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz} + name: regenerator-runtime + version: 0.14.0 + dev: false + + registry.npmmirror.com/resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz} + name: resize-observer-polyfill + version: 1.5.1 + dev: false + + registry.npmmirror.com/resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz} + name: resolve-from + version: 4.0.0 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz} + name: reusify + version: 1.0.4 + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz} + name: rimraf + version: 3.0.2 + hasBin: true + dependencies: + glob: registry.npmmirror.com/glob@7.2.3 + dev: true + + registry.npmmirror.com/rollup@4.6.1: + resolution: {integrity: sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/rollup/-/rollup-4.6.1.tgz} + name: rollup + version: 4.6.1 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + '@rollup/rollup-android-arm-eabi': registry.npmmirror.com/@rollup/rollup-android-arm-eabi@4.6.1 + '@rollup/rollup-android-arm64': registry.npmmirror.com/@rollup/rollup-android-arm64@4.6.1 + '@rollup/rollup-darwin-arm64': registry.npmmirror.com/@rollup/rollup-darwin-arm64@4.6.1 + '@rollup/rollup-darwin-x64': registry.npmmirror.com/@rollup/rollup-darwin-x64@4.6.1 + '@rollup/rollup-linux-arm-gnueabihf': registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf@4.6.1 + '@rollup/rollup-linux-arm64-gnu': registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu@4.6.1 + '@rollup/rollup-linux-arm64-musl': registry.npmmirror.com/@rollup/rollup-linux-arm64-musl@4.6.1 + '@rollup/rollup-linux-x64-gnu': registry.npmmirror.com/@rollup/rollup-linux-x64-gnu@4.6.1 + '@rollup/rollup-linux-x64-musl': registry.npmmirror.com/@rollup/rollup-linux-x64-musl@4.6.1 + '@rollup/rollup-win32-arm64-msvc': registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc@4.6.1 + '@rollup/rollup-win32-ia32-msvc': registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc@4.6.1 + '@rollup/rollup-win32-x64-msvc': registry.npmmirror.com/@rollup/rollup-win32-x64-msvc@4.6.1 + fsevents: registry.npmmirror.com/fsevents@2.3.3 + dev: true + + registry.npmmirror.com/run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz} + name: run-parallel + version: 1.2.0 + dependencies: + queue-microtask: registry.npmmirror.com/queue-microtask@1.2.3 + dev: true + + registry.npmmirror.com/sass@1.69.5: + resolution: {integrity: sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sass/-/sass-1.69.5.tgz} + name: sass + version: 1.69.5 + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: registry.npmmirror.com/chokidar@3.5.3 + immutable: registry.npmmirror.com/immutable@4.3.4 + source-map-js: registry.npmmirror.com/source-map-js@1.0.2 + + registry.npmmirror.com/scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz} + name: scheduler + version: 0.23.0 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + dev: false + + registry.npmmirror.com/scroll-into-view-if-needed@2.2.31: + resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz} + name: scroll-into-view-if-needed + version: 2.2.31 + dependencies: + compute-scroll-into-view: registry.npmmirror.com/compute-scroll-into-view@1.0.20 + dev: false + + registry.npmmirror.com/semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz} + name: semver + version: 6.3.1 + hasBin: true + dev: true + + registry.npmmirror.com/semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz} + name: semver + version: 7.5.4 + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: registry.npmmirror.com/lru-cache@6.0.0 + dev: true + + registry.npmmirror.com/shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz} + name: shebang-command + version: 2.0.0 + engines: {node: '>=8'} + dependencies: + shebang-regex: registry.npmmirror.com/shebang-regex@3.0.0 + dev: true + + registry.npmmirror.com/shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz} + name: shebang-regex + version: 3.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz} + name: slash + version: 3.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/snake-case/-/snake-case-3.0.4.tgz} + name: snake-case + version: 3.0.4 + dependencies: + dot-case: registry.npmmirror.com/dot-case@3.0.4 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: true + + registry.npmmirror.com/source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz} + name: source-map-js + version: 1.0.2 + engines: {node: '>=0.10.0'} + + registry.npmmirror.com/strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz} + name: strip-ansi + version: 6.0.1 + engines: {node: '>=8'} + dependencies: + ansi-regex: registry.npmmirror.com/ansi-regex@5.0.1 + dev: true + + registry.npmmirror.com/strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz} + name: strip-json-comments + version: 3.1.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz} + name: supports-color + version: 5.5.0 + engines: {node: '>=4'} + dependencies: + has-flag: registry.npmmirror.com/has-flag@3.0.0 + dev: true + + registry.npmmirror.com/supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz} + name: supports-color + version: 7.2.0 + engines: {node: '>=8'} + dependencies: + has-flag: registry.npmmirror.com/has-flag@4.0.0 + dev: true + + registry.npmmirror.com/svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz} + name: svg-parser + version: 2.0.4 + dev: true + + registry.npmmirror.com/text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz} + name: text-table + version: 0.2.0 + dev: true + + registry.npmmirror.com/to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz} + name: to-fast-properties + version: 2.0.0 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz} + name: to-regex-range + version: 5.0.1 + engines: {node: '>=8.0'} + dependencies: + is-number: registry.npmmirror.com/is-number@7.0.0 + + registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.2.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz} + id: registry.npmmirror.com/ts-api-utils/1.0.3 + name: ts-api-utils + version: 1.0.3 + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: registry.npmmirror.com/typescript@5.2.2 + dev: true + + registry.npmmirror.com/tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz} + name: tslib + version: 2.3.0 + dev: false + + registry.npmmirror.com/tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz} + name: tslib + version: 2.6.2 + + registry.npmmirror.com/type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz} + name: type-check + version: 0.4.0 + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + dev: true + + registry.npmmirror.com/type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz} + name: type-fest + version: 0.20.2 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typescript/-/typescript-5.2.2.tgz} + name: typescript + version: 5.2.2 + engines: {node: '>=14.17'} + hasBin: true + dev: true + + registry.npmmirror.com/update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz} + id: registry.npmmirror.com/update-browserslist-db/1.0.13 + name: update-browserslist-db + version: 1.0.13 + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: registry.npmmirror.com/browserslist@4.22.1 + escalade: registry.npmmirror.com/escalade@3.1.1 + picocolors: registry.npmmirror.com/picocolors@1.0.0 + dev: true + + registry.npmmirror.com/uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz} + name: uri-js + version: 4.4.1 + dependencies: + punycode: registry.npmmirror.com/punycode@2.3.1 + dev: true + + registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz} + id: registry.npmmirror.com/use-sync-external-store/1.2.0 + name: use-sync-external-store + version: 1.2.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: registry.npmmirror.com/react@18.2.0 + dev: false + + registry.npmmirror.com/utility-types@3.10.0: + resolution: {integrity: sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/utility-types/-/utility-types-3.10.0.tgz} + name: utility-types + version: 3.10.0 + engines: {node: '>= 4'} + dev: false + + registry.npmmirror.com/vite-plugin-svgr@4.2.0(typescript@5.2.2)(vite@5.0.0): + resolution: {integrity: sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz} + id: registry.npmmirror.com/vite-plugin-svgr/4.2.0 + name: vite-plugin-svgr + version: 4.2.0 + peerDependencies: + vite: ^2.6.0 || 3 || 4 || 5 + dependencies: + '@rollup/pluginutils': registry.npmmirror.com/@rollup/pluginutils@5.1.0 + '@svgr/core': registry.npmmirror.com/@svgr/core@8.1.0(typescript@5.2.2) + '@svgr/plugin-jsx': registry.npmmirror.com/@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0) + vite: registry.npmmirror.com/vite@5.0.0(sass@1.69.5) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + dev: true + + registry.npmmirror.com/vite@5.0.0(sass@1.69.5): + resolution: {integrity: sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vite/-/vite-5.0.0.tgz} + id: registry.npmmirror.com/vite/5.0.0 + name: vite + version: 5.0.0 + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: registry.npmmirror.com/esbuild@0.19.8 + postcss: registry.npmmirror.com/postcss@8.4.31 + rollup: registry.npmmirror.com/rollup@4.6.1 + sass: registry.npmmirror.com/sass@1.69.5 + optionalDependencies: + fsevents: registry.npmmirror.com/fsevents@2.3.3 + dev: true + + registry.npmmirror.com/which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which/-/which-2.0.2.tgz} + name: which + version: 2.0.2 + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: registry.npmmirror.com/isexe@2.0.0 + dev: true + + registry.npmmirror.com/wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz} + name: wrappy + version: 1.0.2 + + registry.npmmirror.com/yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz} + name: yallist + version: 3.1.1 + dev: true + + registry.npmmirror.com/yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz} + name: yallist + version: 4.0.0 + dev: true + + registry.npmmirror.com/yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz} + name: yocto-queue + version: 0.1.0 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/zrender@5.4.4: + resolution: {integrity: sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz} + name: zrender + version: 5.4.4 + dependencies: + tslib: registry.npmmirror.com/tslib@2.3.0 + dev: false + + registry.npmmirror.com/zustand@4.3.8(react@18.2.0): + resolution: {integrity: sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/zustand/-/zustand-4.3.8.tgz} + id: registry.npmmirror.com/zustand/4.3.8 + name: zustand + version: 4.3.8 + engines: {node: '>=12.7.0'} + peerDependencies: + immer: '>=9.0' + react: '>=16.8' + peerDependenciesMeta: + immer: + optional: true + react: + optional: true + dependencies: + react: registry.npmmirror.com/react@18.2.0 + use-sync-external-store: registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.2.0) + dev: false diff --git a/webapp/public/logo.svg b/webapp/public/logo.svg new file mode 100644 index 000000000..a562a957a --- /dev/null +++ b/webapp/public/logo.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx new file mode 100644 index 000000000..232e56163 --- /dev/null +++ b/webapp/src/App.tsx @@ -0,0 +1,117 @@ +import "./styles/globals.scss"; +import { ErrorBoundary } from './components/error'; +import { + HashRouter as Router, + Routes, + Route +} from "react-router-dom"; +import { Login } from './components/login'; +import { RootLayout as Layout } from './components/layout'; +import { hasPagePermission, routers } from './router'; +import { Empty, LocaleProvider } from '@douyinfe/semi-ui'; +import { getSemiLang } from './locales'; +import { useAccessStore, useConfigStore } from './store'; +import { useEffect } from 'react'; +import { getCSSVar } from './utils/utils'; +import { IllustrationIdle, IllustrationIdleDark } from '@douyinfe/semi-illustrations'; +import Cookies from 'js-cookie'; + +function App() { + return ( + <> + + + + + + + + + ) +} + +function Screen() { + useSwitchTheme() + const access = useAccessStore(); + useEffect(() => { + const token = Cookies.get('token'); + if (token) { + access.updateToken(token); + Cookies.remove('token'); + } + }, []) + return ( + <> + {access.isAuthorized() ? ( + + + {routers.flatMap(router => { + return hasPagePermission(router, access) ? [] : []; + })} + {/* Default page */} + } key={"*"} /> + + + ) : ( + <> + + + )} + + ); +} + +function Home() { + const access = useAccessStore(); + return ( +
+ } + darkModeImage={} + description={`Welcome, ${access.userName} 🌻🌻🌻`} + style={{ fontSize: '22px' }} + /> +
+ ) +} + +function useSwitchTheme() { + const config = useConfigStore(); + + useEffect(() => { + document.body.classList.remove("light"); + document.body.classList.remove("dark"); + + if (config.theme === "dark") { + document.body.classList.add("dark"); + document.body.setAttribute("theme-mode", "dark"); + } else if (config.theme === "light") { + document.body.classList.add("light"); + document.body.removeAttribute("theme-mode"); + } + + const metaDescriptionDark = document.querySelector( + 'meta[name="theme-color"][media*="dark"]', + ); + const metaDescriptionLight = document.querySelector( + 'meta[name="theme-color"][media*="light"]', + ); + + if (config.theme === "auto") { + metaDescriptionDark?.setAttribute("content", "#151515"); + metaDescriptionLight?.setAttribute("content", "#fafafa"); + + if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + document.body.setAttribute("theme-mode", "dark"); + } else { + document.body.removeAttribute("theme-mode"); + } + } else { + const themeColor = getCSSVar("--theme-color"); + metaDescriptionDark?.setAttribute("content", themeColor); + metaDescriptionLight?.setAttribute("content", themeColor); + } + }, [config.theme]); +} + +export default App diff --git a/webapp/src/api/base.ts b/webapp/src/api/base.ts new file mode 100644 index 000000000..37d955f5e --- /dev/null +++ b/webapp/src/api/base.ts @@ -0,0 +1,138 @@ +import { useAccessStore } from "../store"; +import Locale, { getServerLang } from "../locales"; +import { Toast } from "@douyinfe/semi-ui"; + +export class ClientApi { + async get(url: string, params: Record = {}): Promise { + let queryString = ""; + if (Object.keys(params).length > 0) { + queryString = "?" + new URLSearchParams(params).toString(); + } + const res: Response = await fetch( + this.path(url + queryString), + { + headers: getHeaders(), + method: "GET" + }); + if (res.status !== 200) { + Toast.error({ + content: Locale.Error.Network, + duration: 5, + theme: "light" + }); + throw new Error(Locale.Error.Network); + } + const resJson = await res.json(); + if (resJson.code === 401) { + Toast.error({ + content: Locale.Auth.Expiration, + duration: 5, + theme: "light" + }); + const accessStore = useAccessStore.getState(); + accessStore.updateToken(""); + throw new Error(Locale.Auth.Expiration); + } else if (resJson.code !== 200) { + Toast.error({ + content: resJson.msg, + duration: 5, + theme: "light" + }); + throw new Error(resJson.msg); + } + return resJson.data; + } + + async post(url: string, body: Record = {}): Promise { + const res: Response = await fetch( + this.path(url), + { + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json", + ...getHeaders() + }, + method: "POST" + }); + if (res.status !== 200) { + Toast.error({ + content: Locale.Error.Network, + duration: 5, + theme: "light" + }); + throw new Error(Locale.Error.Network); + } + const resJson = await res.json(); + if (resJson.code === 401) { + Toast.error({ + content: Locale.Auth.Expiration, + duration: 5, + theme: "light" + }); + const accessStore = useAccessStore.getState(); + accessStore.updateToken(""); + throw new Error(Locale.Auth.Expiration); + } else if (resJson.code !== 200) { + Toast.error({ + content: resJson.msg, + duration: 5, + theme: "light" + }); + throw new Error(resJson.msg); + } + return resJson.data; + } + + async postForm(url: string, formData: FormData = new FormData()): Promise { + const res: Response = await fetch( + this.path(url), + { + body: formData, + headers: getHeaders(), + method: "POST", + redirect: "follow" + }); + if (res.status !== 200) { + Toast.error({ + content: Locale.Error.Network, + duration: 5, + theme: "light" + }); + throw new Error(Locale.Error.Network); + } + const resJson = await res.json(); + if (resJson.code !== 200) { + Toast.error({ + content: resJson.msg, + duration: 5, + theme: "light" + }); + throw new Error(resJson.msg); + } + return resJson.data; + } + + path(path: string): string { + const proxyPath = import.meta.env.VITE_PROXY_PATH; + return [proxyPath, path].join(""); + } +} + +export const api = new ClientApi(); + +export function getHeaders(): Record { + const accessStore = useAccessStore.getState(); + const headers: Record = { + "x-requested-with": "XMLHttpRequest", + "Content-Language": getServerLang(), + }; + + const makeBearer = (token: string) => `Bearer ${token.trim()}`; + const validString = (x: string) => x && x.length > 0; + + if (validString(accessStore.token)) { + headers.Authorization = makeBearer(accessStore.token); + } + + return headers; +} diff --git a/webapp/src/api/webapp/cluster.ts b/webapp/src/api/webapp/cluster.ts new file mode 100644 index 000000000..a93d39b4d --- /dev/null +++ b/webapp/src/api/webapp/cluster.ts @@ -0,0 +1,18 @@ +import { BackendData } from "../../types/cluster"; +import { api } from "../base"; + +export async function backendsApi(body: Record): Promise { + return api.post('/webapp/getAllBackends', body) +} + +export async function backendSaveApi(body: Record): Promise { + return api.post('/webapp/saveBackend', body) +} + +export async function backendUpdateApi(body: Record): Promise { + return api.post('/webapp/updateBackend', body) +} + +export async function backendDeleteApi(body: Record): Promise { + return api.post('/webapp/deleteBackend', body) +} diff --git a/webapp/src/api/webapp/dashboard.ts b/webapp/src/api/webapp/dashboard.ts new file mode 100644 index 000000000..fa3c1ebea --- /dev/null +++ b/webapp/src/api/webapp/dashboard.ts @@ -0,0 +1,6 @@ +import { DistributionDetail } from "../../types/dashboard"; +import { api } from "../base"; + +export async function distributionApi(body: Record): Promise { + return api.post('/webapp/getDistribution', body) +} diff --git a/webapp/src/api/webapp/global-property.ts b/webapp/src/api/webapp/global-property.ts new file mode 100644 index 000000000..864fe5a77 --- /dev/null +++ b/webapp/src/api/webapp/global-property.ts @@ -0,0 +1,21 @@ +import { api } from "../base"; + +export async function globalPropertiesApi(body: Record): Promise { + return api.post('/webapp/findGlobalProperty', body) +} + +export async function globalPropertyGetApi(body: Record): Promise { + return api.post('/webapp/getGlobalProperty', body) +} + +export async function globalPropertySaveApi(body: Record): Promise { + return api.post('/webapp/saveGlobalProperty', body) +} + +export async function globalPropertyUpdateApi(body: Record): Promise { + return api.post('/webapp/updateGlobalProperty', body) +} + +export async function globalPropertyDeleteApi(body: Record): Promise { + return api.post('/webapp/deleteGlobalProperty', body) +} diff --git a/webapp/src/api/webapp/history.ts b/webapp/src/api/webapp/history.ts new file mode 100644 index 000000000..48105f25a --- /dev/null +++ b/webapp/src/api/webapp/history.ts @@ -0,0 +1,6 @@ +import { HistoryData } from "../../types/history"; +import { api } from "../base"; + +export async function queryHistoryApi(body: Record): Promise { + return api.post('/webapp/findQueryHistory', body) +} diff --git a/webapp/src/api/webapp/login.ts b/webapp/src/api/webapp/login.ts new file mode 100644 index 000000000..392114f46 --- /dev/null +++ b/webapp/src/api/webapp/login.ts @@ -0,0 +1,21 @@ +import { api } from "../base"; + +export async function loginFormApi(body: Record): Promise { + return api.post('/login', body) +} + +export async function logoutApi(body: Record): Promise { + return api.post('/logout', body) +} + +export async function loginOAuthApi(body: Record): Promise { + return api.post('/sso', body) +} + +export async function getInfoApi(): Promise { + return api.post('/userinfo', {}) +} + +export async function loginTypeApi(): Promise { + return api.post('/loginType', {}) +} diff --git a/webapp/src/api/webapp/resource-group.ts b/webapp/src/api/webapp/resource-group.ts new file mode 100644 index 000000000..55b503e92 --- /dev/null +++ b/webapp/src/api/webapp/resource-group.ts @@ -0,0 +1,22 @@ +import { ResourceGroupData } from "../../types/resource-group"; +import { api } from "../base"; + +export async function resourceGroupsApi(body: Record): Promise { + return api.post('/webapp/findResourceGroup', body) +} + +export async function resourceGroupGetApi(body: Record): Promise { + return api.post('/webapp/getResourceGroup', body) +} + +export async function resourceGroupSaveApi(body: Record): Promise { + return api.post('/webapp/saveResourceGroup', body) +} + +export async function resourceGroupUpdateApi(body: Record): Promise { + return api.post('/webapp/updateResourceGroup', body) +} + +export async function resourceGroupDeleteApi(body: Record): Promise { + return api.post('/webapp/deleteResourceGroup', body) +} diff --git a/webapp/src/api/webapp/selector.ts b/webapp/src/api/webapp/selector.ts new file mode 100644 index 000000000..0b479de9f --- /dev/null +++ b/webapp/src/api/webapp/selector.ts @@ -0,0 +1,22 @@ +import { SelectorData } from "../../types/selector"; +import { api } from "../base"; + +export async function selectorsApi(body: Record): Promise { + return api.post('/webapp/findSelector', body) +} + +export async function selectorGetApi(body: Record): Promise { + return api.post('/webapp/getSelector', body) +} + +export async function selectorSaveApi(body: Record): Promise { + return api.post('/webapp/saveSelector', body) +} + +export async function selectorUpdateApi(body: Record): Promise { + return api.post('/webapp/updateSelector', body) +} + +export async function selectorDeleteApi(body: Record): Promise { + return api.post('/webapp/deleteSelector', body) +} diff --git a/webapp/src/assets/logo.svg b/webapp/src/assets/logo.svg new file mode 100644 index 000000000..a562a957a --- /dev/null +++ b/webapp/src/assets/logo.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webapp/src/components/cluster.module.scss b/webapp/src/components/cluster.module.scss new file mode 100644 index 000000000..9c72aa486 --- /dev/null +++ b/webapp/src/components/cluster.module.scss @@ -0,0 +1,8 @@ +.description{ + padding: 10px; +} + +.card { + background-color: var(--semi-color-bg-1); + width: 100%; +} diff --git a/webapp/src/components/cluster.tsx b/webapp/src/components/cluster.tsx new file mode 100644 index 000000000..99ee70d07 --- /dev/null +++ b/webapp/src/components/cluster.tsx @@ -0,0 +1,211 @@ +import { useEffect, useState } from "react"; +import styles from './cluster.module.scss'; +import Locale from "../locales"; +import { backendDeleteApi, backendSaveApi, backendUpdateApi, backendsApi } from "../api/webapp/cluster"; +import { Button, ButtonGroup, Card, Form, Modal, Popconfirm, Switch, Table, Typography } from "@douyinfe/semi-ui"; +import Column from "@douyinfe/semi-ui/lib/es/table/Column"; +import { FormApi } from "@douyinfe/semi-ui/lib/es/form"; +import { Role, useAccessStore } from "../store"; +import { BackendData } from "../types/cluster"; + +export function Cluster() { + const { Text } = Typography; + const access = useAccessStore(); + const [backendData, setBackendData] = useState(); + const [visibleForm, setVisibleForm] = useState(false); + const [formApi, setFormApi] = useState>(); + const [form, setForm] = useState(); + + useEffect(() => { + list(); + }, []); + + const list = () => { + backendsApi({}) + .then(data => { + setBackendData(data); + }).catch(() => { }); + } + + const linkRender = (text: string) => { + return ( + {text} + ); + } + + const switchRender = (text: boolean, record: BackendData) => { + return ( + + ); + } + + const operateRender = (_text: any, record: BackendData) => { + return ( + + + { + backendDeleteApi({ name: record.name }) + .then(data => { + console.log(data) + list(); + }).catch(() => { }); + }} + > + + + + ); + } + + return ( + <> + + + + b.routingGroup))] + .map(routingGroup => { + return { + text: routingGroup, + value: routingGroup + } + })} + onFilter={(value, record) => { + return value === record.routingGroup + }} /> + + + + + + {access.hasRole(Role.ADMIN) && ( + + + + + } dataIndex="operate" key="operate" render={operateRender} /> + )} +
+
+ { formApi?.submitForm() }} + onCancel={() => { setVisibleForm(false) }} + centered + width={500} + height={500} + bodyStyle={{ overflow: 'auto' }} + > +
{ + if (form === undefined) { + backendSaveApi(values) + .then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } else { + backendUpdateApi(values) + .then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } + }} + getFormApi={setFormApi} + > + + + + + + +
+ + ); +} + +const SwitchRender = (props: { + text: boolean; + record: BackendData; + list: () => void; +}) => { + const access = useAccessStore(); + const [loading, setLoading] = useState(false); + + const handleSwitchChange = (v: boolean) => { + setLoading(true); + props.record.active = v; + backendUpdateApi(props.record) + .then(data => { + console.log(data); + setLoading(false); + props.list(); + }).catch(() => { }); + }; + + return ( + + ); +} diff --git a/webapp/src/components/dashboard.module.scss b/webapp/src/components/dashboard.module.scss new file mode 100644 index 000000000..d33250265 --- /dev/null +++ b/webapp/src/components/dashboard.module.scss @@ -0,0 +1,26 @@ +.description { + padding: 10px; + + .tip { + display: flex; + + .title { + margin-right: 5px; + } + + .help { + display: flex; + align-items: center; + justify-content: center; + } + } + + .linkText:hover { + cursor: pointer; + text-decoration: underline; + } +} + +.card { + background-color: var(--semi-color-bg-1); +} diff --git a/webapp/src/components/dashboard.tsx b/webapp/src/components/dashboard.tsx new file mode 100644 index 000000000..dc28797af --- /dev/null +++ b/webapp/src/components/dashboard.tsx @@ -0,0 +1,248 @@ +import { useEffect, useRef, useState } from "react"; +import Locale from "../locales"; +import styles from './dashboard.module.scss'; +import * as echarts from "echarts"; +import { Card, Col, Descriptions, Row, Tooltip } from "@douyinfe/semi-ui"; +import { distributionApi } from "../api/webapp/dashboard"; +import { DistributionDetail, DistributionChartData, LineChartData } from "../types/dashboard"; +import { getCSSVar } from "../utils/utils"; +import { IconHelpCircle } from "@douyinfe/semi-icons"; +import { useNavigate } from "react-router-dom"; +import { hasPagePermission, routersMapper } from "../router"; +import { useAccessStore } from "../store"; + +export function Dashboard() { + const access = useAccessStore(); + const navigate = useNavigate(); + const [distributionDetail, setDistributionDetail] = useState(); + + useEffect(() => { + distributionApi({}) + .then(data => { + setDistributionDetail(data); + }).catch(() => { }); + }, []); + + const data = [ + { + key: Locale.Dashboard.StartTime, + value: distributionDetail?.startTime + }, + { + key: Locale.Dashboard.Backends, + value: hasPagePermission(routersMapper['cluster'], access) + ? { + const router = routersMapper['cluster']; + if (router && router.routeProps && router.routeProps.path) { + navigate(router.routeProps.path); + } + }}>{distributionDetail?.totalBackendCount} + : {distributionDetail?.totalBackendCount} + + }, + { + key: Locale.Dashboard.BackendsOnline, + value: distributionDetail?.onlineBackendCount, + }, + { + key: Locale.Dashboard.BackendsOffline, + value: distributionDetail?.offlineBackendCount + }, + { + key: ( +
+ {Locale.Dashboard.QPH} + + + + + +
+ ), + value: distributionDetail?.totalQueryCount + }, + { + key: ( +
+ {Locale.Dashboard.QPM} + + + + + +
+ ), + value: distributionDetail?.averageQueryCountMinute.toFixed(2) + }, + { + key: ( +
+ {Locale.Dashboard.QPS} + + + + + +
+ ), + value: distributionDetail?.averageQueryCountSecond.toFixed(2) + }, + ]; + + return ( + <> +
+ + + + + + + + + + + + + + + + + + + +
+ + ); +} + +function LineChart(props: { + data: Record +}) { + const chartRef = useRef(null); + + useEffect(() => { + const chartInstance = echarts.init(chartRef.current); + let minMinute = 2400; + let maxMinute = 0; + Object.keys(props.data).forEach(d => { + const lineChartDatas = props.data[d] + const lineChartDataTemp = lineChartDatas.map(lineChartData => parseInt(lineChartData.minute.replace(":", ""))) + const minMinuteTemp = Math.min(...lineChartDataTemp); + const maxMinuteTemp = Math.max(...lineChartDataTemp); + if (minMinuteTemp < minMinute) { + minMinute = minMinuteTemp; + } + if (maxMinuteTemp > maxMinute) { + maxMinute = maxMinuteTemp; + } + }); + const minuteStrings: string[] = []; + for (let i = minMinute; i <= maxMinute; i++) { + if ((i % 100) >= 60) { + continue; + } + const hour = Math.floor(i / 100).toString().padStart(2, "0"); + const minute = (i % 100).toString().padStart(2, "0"); + minuteStrings.push(`${hour}:${minute}`); + } + const option = { + legend: { + textStyle: { + color: getCSSVar('--semi-color-text-0') + } + }, + xAxis: { + type: 'category', + data: minuteStrings + }, + yAxis: { + type: 'value', + minInterval: 1 + }, + tooltip: { + trigger: 'axis' + }, + series: Object.keys(props.data).map(d => { + const lineChartDatas = props.data[d].reduce((obj, item) => { + obj[item.minute] = item.queryCount; + return obj; + }, {} as Record); + return { + name: d, + data: minuteStrings.map(m => lineChartDatas[m] || 0), + type: 'line', + smooth: true + } + }) + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + chartInstance.setOption(option); + }, [props.data]); + + return ( +
+
+
+ ); +} + +function DistributionChart(props: { + data: DistributionChartData[] +}) { + const chartRef = useRef(null); + + useEffect(() => { + const chartInstance = echarts.init(chartRef.current); + const option = { + tooltip: { + trigger: 'item' + }, + legend: { + textStyle: { + color: getCSSVar('--semi-color-text-0') + } + }, + series: [ + { + name: Locale.Dashboard.QueryCount, + type: 'pie', + radius: ['40%', '70%'], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 10, + borderColor: '#fff', + borderWidth: 2 + }, + label: { + show: false, + position: 'center', + }, + emphasis: { + label: { + show: true, + fontSize: 17, + fontWeight: 'bold' + } + }, + labelLine: { + show: false + }, + data: props.data.map(d => { + return { value: d.queryCount, name: d.name } + }) + } + ] + }; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + chartInstance.setOption(option); + }, [props.data]); + + return ( +
+
+
+ ); +} diff --git a/webapp/src/components/error.tsx b/webapp/src/components/error.tsx new file mode 100644 index 000000000..76bdac8fc --- /dev/null +++ b/webapp/src/components/error.tsx @@ -0,0 +1,40 @@ +import React from "react"; + +interface IErrorBoundaryState { + hasError: boolean; + error: Error | null; + info: React.ErrorInfo | null; +} + +interface IErrorBoundaryProps { + children: React.ReactNode; +} + +export class ErrorBoundary extends React.Component { + constructor(props: IErrorBoundaryProps) { + super(props); + this.state = { hasError: false, error: null, info: null }; + } + + componentDidCatch(error: Error, info: React.ErrorInfo) { + // Update state with error details + this.setState({ hasError: true, error, info }); + } + + render() { + if (this.state.hasError) { + // Render error message + return ( +
+

Oops, something went wrong!

+
+            {this.state.error?.toString()}
+            {this.state.info?.componentStack}
+          
+
+ ); + } + // if no error occurred, render children + return this.props.children; + } +} diff --git a/webapp/src/components/history.module.scss b/webapp/src/components/history.module.scss new file mode 100644 index 000000000..9c72aa486 --- /dev/null +++ b/webapp/src/components/history.module.scss @@ -0,0 +1,8 @@ +.description{ + padding: 10px; +} + +.card { + background-color: var(--semi-color-bg-1); + width: 100%; +} diff --git a/webapp/src/components/history.tsx b/webapp/src/components/history.tsx new file mode 100644 index 000000000..098f6c193 --- /dev/null +++ b/webapp/src/components/history.tsx @@ -0,0 +1,122 @@ +import { useEffect, useState } from "react"; +import styles from './history.module.scss'; +import Locale from "../locales"; +import { Button, Card, Form, Table, Tag, Typography } from "@douyinfe/semi-ui"; +import Column from "@douyinfe/semi-ui/lib/es/table/Column"; +import { queryHistoryApi } from "../api/webapp/history"; +import { HistoryData, HistoryDetail } from "../types/history"; +import { formatYYYYMMddHHMMSS } from "../utils/time"; +import { backendsApi } from "../api/webapp/cluster"; +import { Role, useAccessStore } from "../store"; +import { BackendData } from "../types/cluster"; + +export function History() { + const { Text } = Typography; + const access = useAccessStore(); + const [backendData, setBackendData] = useState(); + const [historyData, setHistoryData] = useState(); + const [backendMapping, setBackendMapping] = useState>({}); + const [page, setPage] = useState(1); + const [size] = useState(15); + const [form, setForm] = useState({ + user: access.userName + }); + + useEffect(() => { + backendsApi({}) + .then(data => { + setBackendData(data); + const mapping: Record = {}; + for (let index = 0; index < data.length; index++) { + const backend = data[index] as BackendData; + mapping[backend.name] = backend.proxyTo; + mapping[backend.proxyTo] = backend.name; + mapping[backend.externalUrl] = backend.name; + } + setBackendMapping(mapping); + }).catch(() => { }); + }, []); + + useEffect(() => { + list(1); + }, [form]); + + const list = (p: number) => { + setPage(p); + queryHistoryApi({ + page: p, + size: size, + ...form + }).then(data => { + setHistoryData(data); + }).catch(() => { }); + } + + const linkQueryRender = (text: string, record: HistoryDetail) => { + return ( + {text} + ); + } + + const linkRender = (text: string) => { + return ( + {text} + ); + } + + const timeRender = (text: number) => { + return ( + {formatYYYYMMddHHMMSS(text)} + ); + } + + const ellipsisRender = (text: string) => { + return ( + {text} + ); + } + + return ( + <> + +
( + <> + + {backendData?.map(b => ( + + {backendMapping[b.proxyTo]} + {b.proxyTo} + + ))} + + + + + + )} + layout='horizontal' + onSubmit={(values) => { + setForm(values) + }} + > +
+ + + + {backendMapping[text]}} /> + + + + + +
+
+ + ); +} diff --git a/webapp/src/components/layout.module.scss b/webapp/src/components/layout.module.scss new file mode 100644 index 000000000..9691d8a7c --- /dev/null +++ b/webapp/src/components/layout.module.scss @@ -0,0 +1,181 @@ +.header { + align-self: stretch; + height: 60px; + width: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 99; + + .navigationHeaderLogo { + height: 50px; + width: 50px; + } + + .dIV { + align-items: center; + column-gap: 16px; + display: inline-flex; + flex-shrink: 0; + + .semiIconsBell { + font-size: 20px; + color: var(--semi-color-text-2); + } + + .avatar { + height: 32px; + width: 32px; + } + } +} + +.sider { + position: fixed; + top: 0; + left: 0; + + .collapsed { + display: flex; + //Two 8-margin + width: calc(100% - 16px); + cursor: pointer; + background-color: var(--semi-color-nav-bg); + position: absolute; + bottom: 0; + height: 40px; + align-items: center; + } + + .nav::-webkit-scrollbar { + display: none; + //Hide scrollbars + } + + .nav { + height: 100vh; + padding-top: 60px; + overflow-y: auto; + + .icon { + height: 20px; + width: 20px; + } + } +} + +.content { + margin-top: 60px; + align-items: flex-start; + display: flex; + flex-basis: 0; + flex-direction: column; + padding: 20px; + row-gap: 24px; + flex-grow: 1; + transition: margin-left 0.3s ease; +} + +.userProfile { + align-items: center; + display: flex; + flex-direction: column; + row-gap: 22px; + flex-shrink: 0; + padding-top: 40px; + + .banner { + align-items: center; + display: flex; + flex-direction: column; + + .frame4159 { + align-items: center; + display: flex; + row-gap: 0; + + .avatar { + height: 72px; + width: 72px; + } + } + + .name { + align-items: center; + display: inline-flex; + flex-direction: column; + text-align: center; + + .richardHendricks { + color: var(--semi-color-text-0); + font-size: 20px; + font-weight: 600; + vertical-align: top; + flex-shrink: 0; + } + + .aRichardHendricks { + color: var(--semi-color-text-2); + font-size: 12px; + font-weight: 400; + line-height: 16px; + vertical-align: top; + flex-shrink: 0; + } + } + } + + .main { + align-items: flex-start; + display: flex; + flex-direction: column; + flex-shrink: 0; + padding: 0 38px 0 24px; + row-gap: 12px; + align-self: stretch; + text-align: left; + letter-spacing: -0.14px; + + .descriptions { + align-items: flex-start; + display: inline-flex; + flex-direction: column; + row-gap: 16px; + flex-shrink: 0; + + .frame4152 { + align-items: center; + column-gap: 12px; + display: inline-flex; + flex-shrink: 0; + + .semiIconsMapPin { + font-size: 24px; + color: var(--semi-color-disabled-text); + } + + .value { + color: var(--semi-color-text-0); + font-size: 14px; + min-width: 61px; + vertical-align: top; + flex-shrink: 0; + } + } + } + + .tags { + align-items: flex-start; + column-gap: 8px; + display: inline-flex; + flex-shrink: 0; + + .tag, + .tag1, + .tag2 { + height: 24px; + margin-right: 5px; + } + } + } +} diff --git a/webapp/src/components/layout.tsx b/webapp/src/components/layout.tsx new file mode 100644 index 000000000..2b2240206 --- /dev/null +++ b/webapp/src/components/layout.tsx @@ -0,0 +1,201 @@ +import { Nav, Avatar, Layout, Dropdown, Button, Toast, Select, Modal, Tag } from '@douyinfe/semi-ui'; +import { IconGithubLogo, IconDoubleChevronRight, IconDoubleChevronLeft, IconMoon, IconSun, IconMark, IconIdCard } from '@douyinfe/semi-icons'; +import styles from './layout.module.scss'; +import { useEffect, useState } from 'react'; +import { Link, useLocation } from "react-router-dom"; +import { hasPagePermission, routers, routersMapper } from '../router'; +import { Theme, useAccessStore, useConfigStore } from '../store'; +import { logoutApi } from '../api/webapp/login'; +import Locale, { ALL_LANG_OPTIONS, AllLangs, Lang, changeLang, getLang } from "../locales"; + +export const RootLayout = (props: { + children: React.ReactNode +}) => { + const access = useAccessStore(); + const config = useConfigStore(); + const location = useLocation(); + const { Header, Sider, Content } = Layout; + const [collapsed, setCollapsed] = useState(false); + const [selectedKey, setSelectedKey] = useState(location.pathname.substring(location.pathname.lastIndexOf('/') + 1)); + const [userProfile, setUserProfile] = useState(false); + + useEffect(() => { + const router = routersMapper[location.pathname]; + if (router && router.itemKey != null && selectedKey !== router.itemKey) { + setSelectedKey(router.itemKey); + } + }, [location]); + + const lonout = () => { + logoutApi({}).then(data => { + console.log(data); + access.updateToken(""); + Toast.success(Locale.Auth.LogoutSuccess); + }).catch(() => { }); + } + + const theme = config.theme; + function nextTheme() { + const themes = [Theme.Auto, Theme.Light, Theme.Dark]; + const themeIndex = themes.indexOf(theme); + const nextIndex = (themeIndex + 1) % themes.length; + const nextTheme = themes[nextIndex]; + config.update((config) => (config.theme = nextTheme)); + } + + return ( + <> + +
+ +
+ + + + + + {props.children} + + +
+ + setUserProfile(false)} + width={400} + height={400} + closable={false} + footer={<>} + > +
+
+
+ + {access.userName} + +
+
+

{access.userName}

+
+
+
+
+
+ +

{access.userId}

+
+
+
+ {access.roles.map(role => ( + {role} + ))} +
+
+
+
+ + ); +} diff --git a/webapp/src/components/login.module.scss b/webapp/src/components/login.module.scss new file mode 100644 index 000000000..53940a2d0 --- /dev/null +++ b/webapp/src/components/login.module.scss @@ -0,0 +1,104 @@ +.main { + width: 100vw; + height: 100vh; + align-items: center; + display: flex; + justify-content: center; + + .login { + align-items: center; + background: var(--semi-color-bg-0); + border-radius: 8px; + box-shadow: var(--login-shadow); + display: flex; + flex-direction: column; + padding: 48px 56px; + row-gap: 30px; + width: 440px; + flex-shrink: 0; + + .component66 { + align-items: center; + border-radius: 8px; + display: inline-flex; + flex-direction: column; + row-gap: 24px; + flex-shrink: 0; + + .logo { + height: 200px; + width: 200px; + flex-shrink: 0; + } + + .header { + align-items: center; + display: inline-flex; + flex-direction: column; + justify-content: center; + row-gap: 6px; + flex-shrink: 0; + + .title { + color: var(--semi-color-text-0); + font-size: 32px; + font-weight: 600; + line-height: 44px; + min-width: 128px; + vertical-align: middle; + flex-shrink: 0; + } + + &>.text { + color: var(--semi-color-text-2); + font-size: 16px; + font-weight: 400; + line-height: 22px; + min-width: 163px; + vertical-align: middle; + flex-shrink: 0; + } + } + } + + .form { + align-items: flex-start; + display: flex; + flex-direction: column; + flex-shrink: 0; + row-gap: 28px; + align-self: stretch; + + .inputs { + align-items: flex-start; + display: flex; + flex-direction: column; + flex-shrink: 0; + row-gap: 24px; + align-self: stretch; + } + + .button { + height: 40px; + width: 440px; + } + } + + .oauth { + align-items: center; + justify-content: center; + display: flex; + + .button { + height: 40px; + width: 440px; + } + } + + .undefined { + align-items: center; + justify-content: center; + display: flex; + } + } +} diff --git a/webapp/src/components/login.tsx b/webapp/src/components/login.tsx new file mode 100644 index 000000000..6b65466b9 --- /dev/null +++ b/webapp/src/components/login.tsx @@ -0,0 +1,130 @@ +import { Form, Button, Toast, Spin } from '@douyinfe/semi-ui'; +import styles from './login.module.scss'; +import Locale from "../locales"; +import { useEffect, useState } from 'react'; +import { FormApi } from '@douyinfe/semi-ui/lib/es/form'; +import { loginFormApi, loginOAuthApi, loginTypeApi } from '../api/webapp/login'; +import { useAccessStore } from '../store'; + +export function Login() { + const access = useAccessStore(); + const [formApi, setFormApi] = useState>(); + const [loginBo, setLoginBo] = useState>({}); + const [loginType, setLoginType] = useState<'form' | 'oauth' | 'none'>(); + + useEffect(() => { + loginTypeApi().then(data => { + setLoginType(data); + }).catch(() => { }); + }, []) + + const submitForm = () => { + if (formApi) { + formApi.validate(['username', 'password']) + .then(() => { + loginFormApi(loginBo).then(data => { + access.updateToken(data.token); + Toast.success(Locale.Auth.LoginSuccess); + }).catch(() => { }); + }).catch(() => { }); + } + } + + const submitOAuth = () => { + loginOAuthApi({}).then(data => { + window.location.href = data; + }).catch(() => { }); + } + + return ( +
+
+
+ +
+

+ {Locale.Auth.tips.tip1} + {Locale.Auth.tips.tip2} + {Locale.Auth.tips.tip3} +

+
+
+ {loginType == 'form' && ( +
+
setLoginBo(values)}> + + + + +
+ )} + {loginType == 'oauth' && ( +
+ +
+ )} + {loginType == 'none' && ( +
+
setLoginBo(values)}> + + + + +
+ )} + {loginType == undefined && ( +
+ +
+ )} +
+
+ ); +} diff --git a/webapp/src/components/resource-group.module.scss b/webapp/src/components/resource-group.module.scss new file mode 100644 index 000000000..9c72aa486 --- /dev/null +++ b/webapp/src/components/resource-group.module.scss @@ -0,0 +1,8 @@ +.description{ + padding: 10px; +} + +.card { + background-color: var(--semi-color-bg-1); + width: 100%; +} diff --git a/webapp/src/components/resource-group.tsx b/webapp/src/components/resource-group.tsx new file mode 100644 index 000000000..3412a824c --- /dev/null +++ b/webapp/src/components/resource-group.tsx @@ -0,0 +1,283 @@ +import { useEffect, useState } from "react"; +import styles from './resource-group.module.scss'; +import Locale from "../locales"; +import { Button, ButtonGroup, Card, Form, Modal, Popconfirm, Table } from "@douyinfe/semi-ui"; +import Column from "@douyinfe/semi-ui/lib/es/table/Column"; +import { FormApi } from "@douyinfe/semi-ui/lib/es/form"; +import { resourceGroupDeleteApi, resourceGroupSaveApi, resourceGroupUpdateApi, resourceGroupsApi } from "../api/webapp/resource-group"; +import { ResourceGroupData } from "../types/resource-group"; +import { Role, useAccessStore } from "../store"; + +export function ResourceGroup() { + const access = useAccessStore(); + const [resourceGroupData, setResourceGroupData] = useState(); + const [visibleForm, setVisibleForm] = useState(false); + const [formApi, setFormApi] = useState>(); + const [form, setForm] = useState(); + const [useSchema, setUseSchema] = useState(); + + useEffect(() => { + list(); + }, []); + + const list = () => { + resourceGroupsApi({}) + .then(data => { + setResourceGroupData(data); + }).catch(() => { }); + } + + const operateRender = (_text: any, record: ResourceGroupData) => { + return ( + + + { + resourceGroupDeleteApi({ + useSchema: useSchema, + data: { + resourceGroupId: record.resourceGroupId + } + }).then(data => { + console.log(data); + list(); + }).catch(() => { }); + }} + > + + + + ); + } + + return ( + <> + +
( + <> + + + + )} + layout='horizontal' + onValueChange={values => setUseSchema(values.useSchema)} + >
+
+ + + + + + + + + + + + + + + + {access.hasRole(Role.ADMIN) && ( + + + + + } dataIndex="operate" key="operate" fixed="right" render={operateRender} /> + )} +
+
+ { formApi?.submitForm(); }} + onCancel={() => { setVisibleForm(false); }} + centered + width={700} + height={700} + bodyStyle={{ overflow: 'auto' }} + > +
{ + if (form === undefined) { + resourceGroupSaveApi({ + useSchema: useSchema, + data: values + }).then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } else { + resourceGroupUpdateApi({ + useSchema: useSchema, + data: values + }).then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } + }} + getFormApi={setFormApi} + > + {form !== undefined && ( + + )} + + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + + + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + + + + +
+ + ); +} diff --git a/webapp/src/components/selector.module.scss b/webapp/src/components/selector.module.scss new file mode 100644 index 000000000..9c72aa486 --- /dev/null +++ b/webapp/src/components/selector.module.scss @@ -0,0 +1,8 @@ +.description{ + padding: 10px; +} + +.card { + background-color: var(--semi-color-bg-1); + width: 100%; +} diff --git a/webapp/src/components/selector.tsx b/webapp/src/components/selector.tsx new file mode 100644 index 000000000..0180c50d4 --- /dev/null +++ b/webapp/src/components/selector.tsx @@ -0,0 +1,208 @@ +import { useEffect, useState } from "react"; +import styles from './selector.module.scss'; +import Locale from "../locales"; +import { Button, ButtonGroup, Card, Form, Modal, Popconfirm, Table } from "@douyinfe/semi-ui"; +import Column from "@douyinfe/semi-ui/lib/es/table/Column"; +import { FormApi } from "@douyinfe/semi-ui/lib/es/form"; +import { selectorDeleteApi, selectorSaveApi, selectorUpdateApi, selectorsApi } from "../api/webapp/selector"; +import { SelectorData } from "../types/selector"; +import { Role, useAccessStore } from "../store"; + +export function Selector() { + const access = useAccessStore(); + const [selectorData, setSelectorData] = useState(); + const [visibleForm, setVisibleForm] = useState(false); + const [formApi, setFormApi] = useState>(); + const [form, setForm] = useState(); + const [useSchema, setUseSchema] = useState(); + + useEffect(() => { + list(); + }, []); + + const list = () => { + selectorsApi({}) + .then(data => { + setSelectorData(data); + }).catch(() => { }); + } + + const operateRender = (_text: any, record: SelectorData) => { + return ( + + + { + selectorDeleteApi({ + useSchema: useSchema, + data: record + }).then(data => { + console.log(data); + list(); + }).catch(() => { }); + }} + > + + + + ); + } + + return ( + <> + +
( + <> + + + + )} + layout='horizontal' + onValueChange={values => setUseSchema(values.useSchema)} + >
+
+ + + + + + + + + + {access.hasRole(Role.ADMIN) && ( + + + + + } dataIndex="operate" key="operate" render={operateRender} /> + )} +
+
+ { formApi?.submitForm() }} + onCancel={() => { setVisibleForm(false) }} + centered + width={600} + height={600} + bodyStyle={{ overflow: 'auto' }} + > +
{ + if (form === undefined) { + selectorSaveApi({ + useSchema: useSchema, + data: values + }).then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } else { + selectorUpdateApi({ + useSchema: useSchema, + data: values, + oldData: form + }).then(data => { + console.log(data); + list(); + setVisibleForm(false); + }).catch(() => { }); + } + }} + getFormApi={setFormApi} + > + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + `${value}`.replace(/\D/g, '')} + min={0} + max={Number.MAX_SAFE_INTEGER} + /> + + + + + + +
+ + ); +} diff --git a/webapp/src/constant.ts b/webapp/src/constant.ts new file mode 100644 index 000000000..ac8673a80 --- /dev/null +++ b/webapp/src/constant.ts @@ -0,0 +1,4 @@ +export enum StoreKey { + Access = "access-control", + Config = "app-config", +} diff --git a/webapp/src/locales/en_US.ts b/webapp/src/locales/en_US.ts new file mode 100644 index 000000000..c0e1f00d8 --- /dev/null +++ b/webapp/src/locales/en_US.ts @@ -0,0 +1,81 @@ +const en_US = { + Error: { + Network: "The network has wandered off, please try again later!", + }, + Dashboard: { + QPH: "QPH", + QPHTip: "The number of queries in the past hour.", + QPS: "Avg. QPS", + QPSTip: "Average number of queries per second in the past hour.", + QPM: "Avg. QPM", + QPMTip: "Average number of queries per minute in the past hour.", + Backends: "Backends", + BackendsOffline: "Backends Offline", + BackendsOnline: "Backends Online", + StartTime: "Started At", + Summary: "Summary", + QueryDistribution: "Query Distribution in last hour.", + QueryCount: "Query Count", + }, + History: { + RoutedToTip: "Default All", + QueryIdTip: "Default All", + }, + Menu: { + Header: { + PersonalCenter: "Profile", + Logout: "Logout" + }, + Sider: { + Dashboard: "Dashboard", + Cluster: "Cluster", + History: "History", + ResourceGroup: "Resource Group", + Selector: "Selector", + } + }, + Auth: { + LoginTitle: "Welcome", + tips: { + tip1: "Sign in", + tip2: " Trino Gateway ", + tip3: "Account" + }, + Username: "Username", + Password: "Password", + PasswordTip: "Input password", + UsernameTip: "Input username", + Login: "Sign in", + OAuth2: "Sign in with External Authentication", + NoneAuthTip: "Password not allowed", + LoginSuccess: "Login Success", + Expiration: "Login has expired, please log in again", + LogoutSuccess: "Logout Success", + }, + Copy: { + Success: "Copied to clipboard", + Failed: "Copy failed, please grant permission to access clipboard", + }, + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + Delete: "Delete", + DeleteTitle: "Are you sure you want to delete?", + DeleteContent: "Once deleted, it cannot be recovered!", + Query: "Query", + }, +}; + +type DeepPartial = T extends object + ? { + [P in keyof T]?: DeepPartial; + } + : T; + +export type LocaleType = typeof en_US; +export type PartialLocaleType = DeepPartial; + +export default en_US; diff --git a/webapp/src/locales/index.ts b/webapp/src/locales/index.ts new file mode 100644 index 000000000..926131d1e --- /dev/null +++ b/webapp/src/locales/index.ts @@ -0,0 +1,93 @@ +import en_US from "./en_US"; +import { merge } from "../utils/merge"; +import type { LocaleType } from "./en_US"; +export type { LocaleType, PartialLocaleType } from "./en_US"; +import { Locale } from '@douyinfe/semi-ui/lib/es/locale/interface'; + +import semi_en_US from '@douyinfe/semi-ui/lib/es/locale/source/en_US'; + +const ALL_LANGS = { + en_US, +}; + +export type Lang = keyof typeof ALL_LANGS; + +export const AllLangs = Object.keys(ALL_LANGS) as Lang[]; + +export const ALL_LANG_OPTIONS: Record = { + en_US: "English", +}; + +export const SERVER_LAND_MAPPER: Record = { + en_US: "en_US", +}; + +export const SEMI_LAND_MAPPER: Record = { + en_US: semi_en_US, +}; + +const LANG_KEY = "lang"; +const DEFAULT_LANG = "en_US"; + +const fallbackLang = en_US; +const targetLang = ALL_LANGS[getLang()] as LocaleType; + +// if target lang missing some fields, it will use fallback lang string +merge(fallbackLang, targetLang); + +export default fallbackLang as LocaleType; + +function getItem(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} + +function setItem(key: string, value: string): void { + try { + localStorage.setItem(key, value); + } catch { + console.error('error') + } +} + +function getLanguage(): string { + try { + return navigator.language.toLowerCase(); + } catch { + return DEFAULT_LANG; + } +} + +export function getLang(): Lang { + const savedLang = getItem(LANG_KEY); + + if (AllLangs.includes((savedLang ?? "") as Lang)) { + return savedLang as Lang; + } + + const lang = getLanguage(); + + for (const option of AllLangs) { + if (lang.includes(option)) { + return option; + } + } + + return DEFAULT_LANG; +} + +export function getServerLang(): string { + return SERVER_LAND_MAPPER[getLang()] +} + +export function getSemiLang(): Locale { + return SEMI_LAND_MAPPER[getLang()] +} + +export function changeLang(lang: Lang): void { + setItem(LANG_KEY, lang); + location.reload(); +} diff --git a/webapp/src/main.tsx b/webapp/src/main.tsx new file mode 100644 index 000000000..e63eef4a8 --- /dev/null +++ b/webapp/src/main.tsx @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/webapp/src/router.tsx b/webapp/src/router.tsx new file mode 100644 index 000000000..fe061b7d9 --- /dev/null +++ b/webapp/src/router.tsx @@ -0,0 +1,121 @@ +import { IconHeart, IconIntro, IconPopover, IconScrollList, IconToast } from "@douyinfe/semi-icons-lab"; +import { NavItemProps, NavItemPropsWithItems, SubNavProps } from "@douyinfe/semi-ui/lib/es/navigation"; +import styles from './components/layout.module.scss'; +import { RouteProps } from "react-router-dom"; +import Locale from "./locales"; +import { Dashboard } from './components/dashboard'; +import { Cluster } from './components/cluster'; +import { History } from './components/history'; +import { Selector } from "./components/selector"; +import { ResourceGroup } from "./components/resource-group"; +import { AccessControlStore, Role } from "./store"; + +export interface SubItemItem extends NavItemPropsWithItems { + routeProps: RouteProps, + roles: Role[] +} + +export interface SubRouterItem extends SubNavProps { + itemKey?: string; + items: (SubItemItem)[], + routeProps?: RouteProps, + roles: Role[] +} + +export interface RouterItem extends NavItemProps { + itemKey?: string; + items?: (SubItemItem)[], + routeProps: RouteProps, + roles: Role[] +} + +export type RouterItems = (RouterItem | SubRouterItem)[] + +export const routers: RouterItems = [ + { + itemKey: '', + text: Locale.Menu.Sider.Dashboard, + icon: , + // Role.**** + roles: [], + routeProps: { + path: '/', + element: < Dashboard /> + }, + }, + { + itemKey: 'cluster', + text: Locale.Menu.Sider.Cluster, + icon: , + roles: [], + routeProps: { + path: '/cluster', + element: < Cluster /> + }, + }, + { + itemKey: 'resource-group', + text: Locale.Menu.Sider.ResourceGroup, + icon: , + roles: [], + routeProps: { + path: '/resource-group', + element: < ResourceGroup /> + }, + }, + { + itemKey: 'selector', + text: Locale.Menu.Sider.Selector, + icon: , + roles: [], + routeProps: { + path: '/selector', + element: < Selector /> + }, + }, + { + itemKey: 'history', + text: Locale.Menu.Sider.History, + icon: , + roles: [], + routeProps: { + path: '/history', + element: < History /> + }, + } +] + +export const routersMapper: Record = routers.reduce((mapper, item) => { + if (item.itemKey && item.routeProps && item.routeProps.path) { + mapper[item.itemKey] = item; + mapper[item.routeProps.path] = item; + } + return mapper; +}, {} as Record); + +export function hasPagePermission(router: RouterItem | SubRouterItem, access: AccessControlStore): boolean { + let parentHasPermission = true; + if (router.items == undefined) { + // First level menu + if (router.roles.length != 0) { + parentHasPermission = router.roles.some(role => access.hasRole(role)); + } + if (parentHasPermission && router.itemKey != undefined) { + parentHasPermission = access.hasPermission(router.itemKey.toString()); + } + } else { + // Second level menu + router.items = router.items.filter(item => { + let chilnHasPermission = true; + if (item.roles.length != 0) { + chilnHasPermission = item.roles.some(role => access.hasRole(role)); + } + if (chilnHasPermission && item.itemKey != undefined) { + chilnHasPermission = access.hasPermission(item.itemKey.toString()); + } + return chilnHasPermission; + }); + parentHasPermission = router.items.length != 0; + } + return parentHasPermission; +} diff --git a/webapp/src/store/access.ts b/webapp/src/store/access.ts new file mode 100644 index 000000000..b12e4b7c5 --- /dev/null +++ b/webapp/src/store/access.ts @@ -0,0 +1,96 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { StoreKey } from "../constant"; +import { getInfoApi } from "../api/webapp/login"; + +export enum Role { + ADMIN = "ADMIN", + API = "API", + USER = "USER", +} + +export interface AccessControlStore { + token: string; + + userId: string; + userName: string; + nickName: string; + userType: string; + email: string; + phonenumber: string; + sex: string; + avatar: string; + permissions: string[]; + roles: string[]; + + updateToken: (_: string) => void; + isAuthorized: () => boolean; + getUserInfo: (_?: boolean) => void; + hasRole: (role: Role) => boolean; + hasPermission: (permission: string | undefined) => boolean; +} + +let fetchState = 0; // 0 not fetch, 1 fetching, 2 done + +export const useAccessStore = create()( + persist( + (set, get) => ({ + token: "", + + userId: "", + userName: "", + nickName: "", + userType: "", + email: "", + phonenumber: "", + sex: "", + avatar: "", + permissions: [], + roles: [], + + updateToken(token: string) { + set(() => ({ token: token?.trim() })); + if (get().token) { + get().getUserInfo(true); + } + }, + isAuthorized() { + get().getUserInfo(); + return ( + !!get().token + ); + }, + getUserInfo(force: boolean = false) { + if ((!get().token) || (!force && fetchState > 0)) return; + fetchState = 1; + getInfoApi().then((data) => { + set(() => ({ ...data })); + }).catch(() => { + // console.error("[Config] failed to fetch config"); + }).finally(() => { + fetchState = 2; + }); + }, + hasRole(role: Role) { + return get().roles.includes(role); + }, + hasPermission(permission: string | undefined) { + const permissions = get().permissions + return permission == undefined || permissions == null || permissions.length == 0 || permissions.includes(permission); + }, + }), + { + name: StoreKey.Access, + version: 1, + migrate(persistedState, version) { + const state = persistedState as AccessControlStore; + + if (version < 1) { + // merge your old config + } + + return state as any; + }, + }, + ), +); diff --git a/webapp/src/store/config.ts b/webapp/src/store/config.ts new file mode 100644 index 000000000..ad5bc9c3a --- /dev/null +++ b/webapp/src/store/config.ts @@ -0,0 +1,55 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { StoreKey } from "../constant"; + +export enum Theme { + Auto = "auto", + Dark = "dark", + Light = "light", +} + +export const DEFAULT_CONFIG = { + avatar: "/logo.svg", + theme: Theme.Auto as Theme, + + fontSize: 14, + sidebarWidth: 270, +}; + +export type AppConfig = typeof DEFAULT_CONFIG; + +export type AppConfigStore = AppConfig & { + reset: () => void; + update: (updater: (config: AppConfig) => void) => void; +}; + +export const useConfigStore = create()( + persist( + (set, get) => ({ + ...DEFAULT_CONFIG, + + reset() { + set(() => ({ ...DEFAULT_CONFIG })); + }, + + update(updater) { + const config = { ...get() }; + updater(config); + set(() => config); + }, + }), + { + name: StoreKey.Config, + version: 1, + migrate(persistedState, version) { + const state = persistedState as AppConfig; + + if (version < 1) { + // merge your old config + } + + return state as any; + }, + }, + ), +); diff --git a/webapp/src/store/index.ts b/webapp/src/store/index.ts new file mode 100644 index 000000000..d319633ec --- /dev/null +++ b/webapp/src/store/index.ts @@ -0,0 +1,2 @@ +export * from "./access"; +export * from "./config"; diff --git a/webapp/src/styles/animation.scss b/webapp/src/styles/animation.scss new file mode 100644 index 000000000..b423b08a2 --- /dev/null +++ b/webapp/src/styles/animation.scss @@ -0,0 +1,23 @@ +@keyframes slide-in { + from { + opacity: 0; + transform: translateY(20px); + } + + to { + opacity: 1; + transform: translateY(0px); + } +} + +@keyframes slide-in-from-top { + from { + opacity: 0; + transform: translateY(-20px); + } + + to { + opacity: 1; + transform: translateY(0px); + } +} diff --git a/webapp/src/styles/globals.scss b/webapp/src/styles/globals.scss new file mode 100644 index 000000000..46abf0aa5 --- /dev/null +++ b/webapp/src/styles/globals.scss @@ -0,0 +1,42 @@ +@import "./animation.scss"; + +// If you need to customize the theme, you have to open this line of code. +// see: https://semi.design/en-US/start/customize-theme +// @import '~@semi-bot/semi-theme-xxxxxx/semi.min.css'; + +// customize +@mixin light { + --login-shadow: 0px 4px 14px 0px #0000001a, 0px 0px 1px 0px #0000004d; + --semi-color-bg-0: rgba(245, 245, 245, 1); +} + +@mixin dark { + --login-shadow: 0px 4px 14px 0px #FFFFFF1a, 0px 0px 1px 0px #FFFFFF4d; +} + +.light { + @include light; +} + +.dark { + @include dark; +} + +:root { + @include light; + + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; +} + +@media (prefers-color-scheme: dark) { + :root { + @include dark; + } +} + +body { + padding: 0; + margin: 0; + color: var(--semi-color-text-0); + background: var(--semi-color-bg-0); +} diff --git a/webapp/src/types/cluster.d.ts b/webapp/src/types/cluster.d.ts new file mode 100644 index 000000000..704a6d54b --- /dev/null +++ b/webapp/src/types/cluster.d.ts @@ -0,0 +1,9 @@ +export interface BackendData { + name: string; + proxyTo: string; + active: boolean; + routingGroup: string; + externalUrl: string; + queued: number; + running: number; +} diff --git a/webapp/src/types/dashboard.d.ts b/webapp/src/types/dashboard.d.ts new file mode 100644 index 000000000..6b9972d82 --- /dev/null +++ b/webapp/src/types/dashboard.d.ts @@ -0,0 +1,24 @@ +export interface DistributionDetail { + totalBackendCount: number; + offlineBackendCount: number; + onlineBackendCount: number; + totalQueryCount: number; + averageQueryCountMinute: number; + averageQueryCountSecond: number; + distributionChart: DistributionChartData[]; + lineChart: Record; + startTime: string; +} + +export interface DistributionChartData { + backendUrl: string; + queryCount: number; + name: string; +} + +export interface LineChartData { + minute: string; + backendUrl: string; + queryCount: number; + name: string; +} diff --git a/webapp/src/types/history.d.ts b/webapp/src/types/history.d.ts new file mode 100644 index 000000000..cafb52f2d --- /dev/null +++ b/webapp/src/types/history.d.ts @@ -0,0 +1,13 @@ +export interface HistoryDetail { + queryId: string; + queryText: string; + user: string; + source: string; + backendUrl: string; + captureTime: number; +} + +export interface HistoryData { + total: number; + rows: HistoryDetail[]; +} diff --git a/webapp/src/types/resource-group.d.ts b/webapp/src/types/resource-group.d.ts new file mode 100644 index 000000000..9f8ec7d83 --- /dev/null +++ b/webapp/src/types/resource-group.d.ts @@ -0,0 +1,15 @@ +export interface ResourceGroupData { + resourceGroupId: number; + name: string; + parent: number; + jmxExport: boolean; + schedulingPolicy: string; + schedulingWeight: number; + softMemoryLimit: string; + maxQueued: number; + hardConcurrencyLimit: number; + softConcurrencyLimit: number; + softCpuLimit: string; + hardCpuLimit: string; + environment: string; +} diff --git a/webapp/src/types/selector.d.ts b/webapp/src/types/selector.d.ts new file mode 100644 index 000000000..85aa63a7d --- /dev/null +++ b/webapp/src/types/selector.d.ts @@ -0,0 +1,9 @@ +export interface SelectorData { + resourceGroupId: number; + priority: number; + userRegex: string; + sourceRegex: string; + queryType: string; + clientTags: string; + selectorResourceEstimate: string; +} diff --git a/webapp/src/utils/merge.ts b/webapp/src/utils/merge.ts new file mode 100644 index 000000000..ad1b62254 --- /dev/null +++ b/webapp/src/utils/merge.ts @@ -0,0 +1,9 @@ +export function merge(target: any, source: any): any { + Object.keys(source).forEach(function (key) { + if (source[key] && typeof source[key] === "object") { + merge((target[key] = target[key] || {}), source[key]); + return; + } + target[key] = source[key]; + }); +} diff --git a/webapp/src/utils/time.ts b/webapp/src/utils/time.ts new file mode 100644 index 000000000..e149bd026 --- /dev/null +++ b/webapp/src/utils/time.ts @@ -0,0 +1,41 @@ +import moment from "moment"; + +export const formatTime = ( + time: number, + options: { showMilliseconds?: boolean; extra?: number }, +) => { + options = { + showMilliseconds: false, + ...options, + }; + + const durationFormatted = options.extra + ? ` (${format(options.extra, options)})` + : ""; + + return `${format(time, options)}${durationFormatted}`; +}; + +const format = ( + time: number, + { showMilliseconds }: { showMilliseconds?: boolean } = {}, +) => { + const formatString = `${time >= 60 * 60 ? "hh:m" : ""}m:ss${showMilliseconds ? ".SS" : "" + }`; + + return moment() + .startOf("day") + .millisecond(time * 1000) + .format(formatString); +}; + +export const formatYYYYMMddHHMMSS = (timestamp: number): string => { + const date = new Date(timestamp); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} diff --git a/webapp/src/utils/token.ts b/webapp/src/utils/token.ts new file mode 100644 index 000000000..ec8139b20 --- /dev/null +++ b/webapp/src/utils/token.ts @@ -0,0 +1,22 @@ +export function estimateTokenLength(input: string): number { + let tokenLength = 0; + + for (let i = 0; i < input.length; i++) { + const charCode = input.charCodeAt(i); + + if (charCode < 128) { + // ASCII character + if (charCode <= 122 && charCode >= 65) { + // a-Z + tokenLength += 0.25; + } else { + tokenLength += 0.5; + } + } else { + // Unicode character + tokenLength += 1.5; + } + } + + return tokenLength; +} diff --git a/webapp/src/utils/utils.ts b/webapp/src/utils/utils.ts new file mode 100644 index 000000000..7cc01e8f5 --- /dev/null +++ b/webapp/src/utils/utils.ts @@ -0,0 +1,171 @@ +import { useEffect, useState } from "react"; +import Locale from "../locales"; +import { Toast } from "@douyinfe/semi-ui"; + +export function trimTopic(topic: string): string { + return topic.replace(/[,。!?”“"、,.!?]*$/, ""); +} + +export async function copyToClipboard(text: string): Promise { + try { + await navigator.clipboard.writeText(text); + Toast.success(Locale.Copy.Success); + } catch (error) { + const textArea = document.createElement("textarea"); + textArea.value = text; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand("copy"); + Toast.success(Locale.Copy.Success); + } catch (error) { + Toast.error(Locale.Copy.Failed); + } + document.body.removeChild(textArea); + } +} + +export function downloadAs(text: string, filename: string): void { + const element = document.createElement("a"); + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + encodeURIComponent(text), + ); + element.setAttribute("download", filename); + element.style.display = "none"; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); +} + +export function isIOS(): boolean { + const userAgent = navigator.userAgent.toLowerCase(); + return /iphone|ipad|ipod/.test(userAgent); +} + +export function isIPad(): boolean { + const userAgent = navigator.userAgent.toLowerCase(); + return /ipad/.test(userAgent); +} + +export function isPc(): boolean { + const userAgent = navigator.userAgent.toLowerCase(); + return /mac|windows/.test(userAgent); +} + +export function containsChinese(str: string): boolean { + const pattern = /[\u4e00-\u9fa5]/; + return pattern.test(str); +} + +export function useWindowSize(): { width: number, height: number } { + const [size, setSize] = useState({ + width: window.innerWidth, + height: window.innerHeight, + }); + + useEffect(() => { + const onResize = () => { + setSize({ + width: window.innerWidth, + height: window.innerHeight, + }); + }; + window.addEventListener("resize", onResize); + return () => { + window.removeEventListener("resize", onResize); + }; + }, []); + + return size; +} + +export const MOBILE_MAX_WIDTH = 600; +export function useMobileScreen(): boolean { + const { width } = useWindowSize(); + return width <= MOBILE_MAX_WIDTH; +} + +export const FULL_SCREEN_MAX_WIDTH = 1080; +export function useFullScreen(): boolean { + const { width } = useWindowSize(); + return width <= FULL_SCREEN_MAX_WIDTH; +} + +export function isFirefox(): boolean { + return ( + typeof navigator !== "undefined" && /firefox/i.test(navigator.userAgent) + ); +} + +export function selectOrCopy(_el: HTMLElement, content: string): boolean { + const currentSelection = window.getSelection(); + if (currentSelection?.type === "Range") { + return false; + } + copyToClipboard(content); + return true; +} + +function getDomContentWidth(dom: HTMLElement): number { + const style = window.getComputedStyle(dom); + const paddingWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight); + const width = dom.clientWidth - paddingWidth; + return width; +} + +function getOrCreateMeasureDom(id: string, init?: (dom: HTMLElement) => void): HTMLElement { + let dom = document.getElementById(id); + if (!dom) { + dom = document.createElement("span"); + dom.style.position = "absolute"; + dom.style.wordBreak = "break-word"; + dom.style.fontSize = "14px"; + dom.style.transform = "translateY(-200vh)"; + dom.style.pointerEvents = "none"; + dom.style.opacity = "0"; + dom.id = id; + document.body.appendChild(dom); + init?.(dom); + } + return dom!; +} + +export function autoGrowTextArea(dom: HTMLTextAreaElement): number { + const measureDom = getOrCreateMeasureDom("__measure"); + const singleLineDom = getOrCreateMeasureDom("__single_measure", (dom) => { + dom.innerText = "TEXT_FOR_MEASURE"; + }); + + const width = getDomContentWidth(dom); + measureDom.style.width = width + "px"; + measureDom.innerText = dom.value !== "" ? dom.value : "1"; + measureDom.style.fontSize = dom.style.fontSize; + const endWithEmptyLine = dom.value.endsWith("\n"); + const height = parseFloat(window.getComputedStyle(measureDom).height); + const singleLineHeight = parseFloat( + window.getComputedStyle(singleLineDom).height, + ); + + const rows = Math.round(height / singleLineHeight) + (endWithEmptyLine ? 1 : 0); + return rows; +} + +export function getCSSVar(varName: string): string { + return getComputedStyle(document.body).getPropertyValue(varName).trim(); +} + + +let isThrottled = false; +// eslint-disable-next-line @typescript-eslint/ban-types +export function throttle(func: Function, throttleTime: number = 1000): void { + if (isThrottled) { + return; + } + isThrottled = true; + func(); + setTimeout(() => { + isThrottled = false; + }, throttleTime); +} diff --git a/webapp/src/vite-env.d.ts b/webapp/src/vite-env.d.ts new file mode 100644 index 000000000..b1f45c786 --- /dev/null +++ b/webapp/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json new file mode 100644 index 000000000..a7fc6fbf2 --- /dev/null +++ b/webapp/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/webapp/tsconfig.node.json b/webapp/tsconfig.node.json new file mode 100644 index 000000000..42872c59f --- /dev/null +++ b/webapp/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts new file mode 100644 index 000000000..1fd7adadf --- /dev/null +++ b/webapp/vite.config.ts @@ -0,0 +1,24 @@ +import { ConfigEnv, defineConfig, loadEnv } from 'vite' +import react from '@vitejs/plugin-react' +import svgr from 'vite-plugin-svgr'; + +// https://vitejs.dev/config/ +export default defineConfig((mode: ConfigEnv) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const env = loadEnv(mode.mode, process.cwd()); + const baseUrl = env.VITE_BASE_URL + const proxyPath = env.VITE_PROXY_PATH; + return { + plugins: [react(), svgr()], + server: { + proxy: { + [proxyPath]: { + target: baseUrl, + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, '') + }, + } + } + } +})