Initial Contribution
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e55f344 --- /dev/null +++ b/LICENSE
@@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. \ No newline at end of file
diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..bb103bf --- /dev/null +++ b/NOTICE
@@ -0,0 +1,172 @@ +# Notices for Jifa + +This content is produced and maintained by the Eclipse Jifa project. + +* Project home: https://projects.eclipse.org/projects/technology.jifa + +## Trademarks + +Eclipse Jifa, and Jifa are trademarks of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License v. 2.0 which is available at +http://www.eclipse.org/legal/epl-2.0. + +SPDX-License-Identifier: EPL-2.0 + +## Source Code + +The project maintains the following source code repositories: + +* https://git.eclipse.org/c/jifa/jifa.git + +## Third-party Content + +This project leverages the following third party content. + +lombok (1.18.6) + +* License: MIT + +commons-io (2.6) + +* License: Apache License 2.0 + +Google Guava (27.1-jre) + +* License: Apache License 2.0 + +Apache Log4j SLF4J Binding (2.11.2) + +* License: Apache License 2.0 + +Google Gson (2.8.6) + +* License: Apache License 2.0 + +Eclipse Vert.x (3.8.3) + +* License: Eclipse Public License 2.0 + +* License: Apache License 2.0 + +SSHJ (0.27.0) + +* License: Apache License 2.0 + +Aliyun OSS SDK For Java (2.8.3) + +* License: Apache License 2.0 + +Eclipse MAT + +* License: Eclipse Public License 1.0 + +JUnit (4.12) + +* License: Eclipse Public License 1.0 + +vue (2.6.10) + +* License: MIT + +axios (0.18.1) + +* License: MIT + +bootstrap-vue (2.0.0-rc.19) + +* License: MIT + +chart.js (2.8.0) + +* License: MIT + +echarts (4.6.0) + +* License: Apache License 2.0 + +element-ui (2.13.1) + +* License: MIT + +font-awesome (4.7.0) + +* License: MIT + +jquery (3.4.1) + +* License: MIT + +node-sass (4.14.0) + +* License: MIT + +popper.js (1.15.0) + +* License: MIT + +sass-loader (7.1.0) + +* License: MIT + +tar (4.4.8) + +* License: ISC + +v-charts (1.9.0) + +* License: MIT + +v-contextmenu (2.8.0) + +* License: MIT + +vue-ads-table-tree (2.4.2) + +* License: MIT + +vue-chartjs (3.4.2) + +* License: MIT + +vue-click-outside (1.0.7) + +* License: MIT + +vue-clipboard2 (0.3.0) + +* License: MIT + +vue-cookies (1.5.13) + +* License: MIT + +vue-i18n (8.9.0) + +* License: MIT + +vue-router (3.0.2) + +* License: MIT + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +## Contributors: + +Alibaba - Initial implementation
diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed24c6c --- /dev/null +++ b/README.md
@@ -0,0 +1,28 @@ +## Introduction + +Eclipse Jifa uses Vert.x as the main backend framework, and uses Vue 2.0 as the frontend framework. + +Currently, supported features: + +Heap dump Analysis: +- Overview +- Leak Suspects +- GC Roots +- Dominator Tree +- Thread Overview +- OQL +- Some other features + +## Quick start +``` +./gradlew build + +cd build/distributions && unzip jifa-0.1.zip && cd jifa-0.1 + +./bin/worker + +Jifa will now be reachable at http://localhost:8102. +``` + +## Licenses +[Eclipse Public License 2.0](https://projects.eclipse.org/license/epl-2.0)
diff --git a/backend/build.gradle b/backend/build.gradle new file mode 100644 index 0000000..6c5c21b --- /dev/null +++ b/backend/build.gradle
@@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +subprojects { + apply plugin: 'java' + + ext { + vertx_version = '3.8.3' + } + + dependencies { + compile 'org.projectlombok:lombok:1.18.6' + annotationProcessor 'org.projectlombok:lombok:1.18.6' + + compile 'commons-io:commons-io:2.6' + compile 'com.google.guava:guava:27.1-jre' + } +}
diff --git a/backend/common/build.gradle b/backend/common/build.gradle new file mode 100644 index 0000000..3f141e0 --- /dev/null +++ b/backend/common/build.gradle
@@ -0,0 +1,28 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +buildscript { + archivesBaseName = 'jifa-common' +} + +dependencies { + compile "org.apache.logging.log4j:log4j-slf4j-impl:2.11.2" + + compile 'com.google.code.gson:gson:2.8.6' + + compile group: 'io.vertx', name: 'vertx-web', version: "${vertx_version}" +} + +compileJava { + targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 +} \ No newline at end of file
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/Constant.java b/backend/common/src/main/java/org/eclipse/jifa/common/Constant.java new file mode 100644 index 0000000..b285887 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/Constant.java
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common; + +public interface Constant { + String HEADER_CONTENT_TYPE_KEY = "Content-Type"; + String CONTENT_TYPE_JSON_FORM = "application/json; charset=UTF-8"; + + int HTTP_GET_OK_STATUS_CODE = 200; + int HTTP_POST_CREATED_STATUS_CODE = 201; + + int HTTP_BAD_REQUEST_STATUS_CODE = 400; + int HTTP_FORBIDDEN_REQUEST_STATUS_CODE = 403; + int HTTP_INTERNAL_SERVER_ERROR_STATUS_CODE = 500; + + String LINE_SEPARATOR = System.lineSeparator(); + + String EMPTY_STRING = ""; +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/aux/ErrorCode.java b/backend/common/src/main/java/org/eclipse/jifa/common/aux/ErrorCode.java new file mode 100644 index 0000000..7deb698 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/aux/ErrorCode.java
@@ -0,0 +1,39 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.aux; + +public enum ErrorCode { + + ILLEGAL_ARGUMENT, + + FILE_DOES_NOT_EXIST, + + TRANSFER_ERROR, + + SANITY_CHECK, + + UNKNOWN_ERROR, + + SHOULD_NOT_REACH_HERE, + ; + + public boolean isFatal() { + switch (this) { + case ILLEGAL_ARGUMENT: + case FILE_DOES_NOT_EXIST: + return false; + default: + return true; + } + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/aux/JifaException.java b/backend/common/src/main/java/org/eclipse/jifa/common/aux/JifaException.java new file mode 100644 index 0000000..d233cda --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/aux/JifaException.java
@@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.aux; + +public class JifaException extends RuntimeException { + + private ErrorCode code = ErrorCode.UNKNOWN_ERROR; + + public JifaException() { + this(ErrorCode.UNKNOWN_ERROR); + } + + public JifaException(String detail) { + this(ErrorCode.UNKNOWN_ERROR, detail); + } + + public JifaException(ErrorCode code) { + this(code, code.name()); + } + + public JifaException(ErrorCode code, String detail) { + super(detail); + this.code = code; + } + + public JifaException(Throwable cause) { + super(cause); + } + + public JifaException(ErrorCode errorCode, Throwable cause) { + super(cause); + this.code = errorCode; + } + + public ErrorCode getCode() { + return code; + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/enums/FileType.java b/backend/common/src/main/java/org/eclipse/jifa/common/enums/FileType.java new file mode 100644 index 0000000..2030d59 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/enums/FileType.java
@@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.enums; + +import static org.eclipse.jifa.common.util.ErrorUtil.shouldNotReachHere; + +public enum FileType { + HEAP_DUMP("heap-dump"), + ; + + private String tag; + + FileType(String tag) { + this.tag = tag; + } + + public static FileType getByTag(String tag) { + for (FileType type : FileType.values()) { + if (type.tag.equals(tag)) { + return type; + } + } + return shouldNotReachHere(); + } + + public String getTag() { + return tag; + } +} + +
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/enums/ProgressState.java b/backend/common/src/main/java/org/eclipse/jifa/common/enums/ProgressState.java new file mode 100644 index 0000000..a168d6a --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/enums/ProgressState.java
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.enums; + +public enum ProgressState { + + NOT_STARTED, + + IN_PROGRESS, + + SUCCESS, + + ERROR, + ; + + public boolean isFinal() { + return this == SUCCESS || this == ERROR; + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/request/PagingRequest.java b/backend/common/src/main/java/org/eclipse/jifa/common/request/PagingRequest.java new file mode 100644 index 0000000..993ccdc --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/request/PagingRequest.java
@@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.request; + +import lombok.Data; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +@Data +public class PagingRequest { + + // start with 1 + private int page; + + private int pageSize; + + public PagingRequest(int page, int pageSize) { + ASSERT.isTrue(page >= 1 && pageSize >= 1); + this.page = page; + this.pageSize = pageSize; + } + + public int from() { + return (page - 1) * pageSize; + } + + public int to(int totalSize) { + return Math.min(from() + pageSize, totalSize); + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/Assertion.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/Assertion.java new file mode 100644 index 0000000..38c5377 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/Assertion.java
@@ -0,0 +1,95 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; + +import java.util.Objects; +import java.util.function.Supplier; + +public abstract class Assertion { + + public static final Assertion ASSERT = new Assertion() { + }; + + protected Assertion() { + } + + public Assertion isTrue(boolean expression, ErrorCode errorCode, Supplier<String> message) { + if (!expression) { + throwEx(errorCode, message.get()); + } + return self(); + } + + public Assertion isTrue(boolean expression, ErrorCode errorCode, String message) { + return isTrue(expression, errorCode, () -> message); + } + + public Assertion isTrue(boolean expression, Supplier<String> message) { + return isTrue(expression, ErrorCode.SANITY_CHECK, message); + } + + public Assertion isTrue(boolean expression, String message) { + return isTrue(expression, ErrorCode.SANITY_CHECK, message); + } + + public Assertion isTrue(boolean expression, ErrorCode errorCode) { + return isTrue(expression, errorCode, errorCode.name()); + } + + public Assertion isTrue(boolean expression) { + return isTrue(expression, ErrorCode.SANITY_CHECK); + } + + public Assertion equals(Object expected, Object actual, ErrorCode errorCode, String message) { + return isTrue(Objects.equals(expected, actual), errorCode, message); + } + + public Assertion equals(Object expected, Object actual, ErrorCode errorCode) { + return equals(expected, actual, errorCode, errorCode.name()); + } + + public Assertion equals(Object expected, Object actual, String message) { + return equals(expected, actual, ErrorCode.SANITY_CHECK, message); + } + + public Assertion equals(Object expected, Object actual) { + return equals(expected, actual, ErrorCode.SANITY_CHECK); + } + + public Assertion notNull(Object object, ErrorCode errorCode, Supplier<String> message) { + return isTrue(object != null, errorCode, message); + } + + public Assertion notNull(Object object, Supplier<String> message) { + return notNull(object, ErrorCode.SANITY_CHECK, message); + } + + public Assertion notNull(Object object, String message) { + return notNull(object, ErrorCode.SANITY_CHECK, () -> message); + } + + public Assertion notNull(Object object) { + return notNull(object, ErrorCode.SANITY_CHECK, ErrorCode.SANITY_CHECK::name); + } + + private Assertion self() { + return this; + } + + protected void throwEx(ErrorCode errorCode, String message) { + throw new JifaException(errorCode, message); + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/ErrorUtil.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/ErrorUtil.java new file mode 100644 index 0000000..d3f972a --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/ErrorUtil.java
@@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ErrorUtil { + + public static String toString(Throwable t) { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } + + public static void throwEx(Exception e) { + throw new JifaException(e); + } + + public static <T> T shouldNotReachHere() { + throw new JifaException(ErrorCode.SHOULD_NOT_REACH_HERE); + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/FileUtil.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/FileUtil.java new file mode 100644 index 0000000..05e6cfc --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/FileUtil.java
@@ -0,0 +1,53 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import org.eclipse.jifa.common.Constant; + +import java.io.*; + +import static org.eclipse.jifa.common.util.ErrorUtil.throwEx; + +public class FileUtil { + + public static String content(File f) { + String result = null; + try { + result = content(new FileInputStream(f)); + } catch (FileNotFoundException e) { + throwEx(e); + } + return result; + } + + public static String content(InputStream in) { + StringBuilder sb = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append(Constant.LINE_SEPARATOR); + } + } catch (IOException e) { + throwEx(e); + } + return sb.toString(); + } + + public static void write(File f, String msg, boolean append) { + try (FileWriter fw = new FileWriter(f, append)) { + fw.write(msg); + } catch (IOException e) { + throwEx(e); + } + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/GsonHolder.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/GsonHolder.java new file mode 100644 index 0000000..1c1ae8a --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/GsonHolder.java
@@ -0,0 +1,21 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import com.google.gson.Gson; + +public class GsonHolder { + + public static final Gson GSON = new Gson(); + +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/HTTPRespGuarder.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/HTTPRespGuarder.java new file mode 100644 index 0000000..bfd5b45 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/HTTPRespGuarder.java
@@ -0,0 +1,96 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import org.eclipse.jifa.common.Constant; +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.vo.ErrorResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; + +import static org.eclipse.jifa.common.util.GsonHolder.GSON; + +public class HTTPRespGuarder implements Constant { + + private static final Logger LOGGER = LoggerFactory.getLogger(HTTPRespGuarder.class); + + public static void ok(RoutingContext context) { + ok(context, commonStatusCodeOf(context.request().method()), null); + } + + public static void ok(RoutingContext context, Object content) { + ok(context, commonStatusCodeOf(context.request().method()), content); + } + + private static void ok(RoutingContext context, int statusCode, Object content) { + HttpServerResponse response = context.response(); + response.putHeader(Constant.HEADER_CONTENT_TYPE_KEY, Constant.CONTENT_TYPE_JSON_FORM).setStatusCode(statusCode); + if (content != null) { + response.end((content instanceof String) ? (String) content : GSON.toJson(content)); + } else { + response.end(); + } + } + + public static void fail(RoutingContext context, Throwable t) { + if (t instanceof InvocationTargetException && t.getCause() != null) { + t = t.getCause(); + } + log(t); + context.response() + .putHeader(Constant.HEADER_CONTENT_TYPE_KEY, Constant.CONTENT_TYPE_JSON_FORM) + .setStatusCode(statusCodeOf(t)) + .end(GSON.toJson(new ErrorResult(t))); + } + + private static int statusCodeOf(Throwable t) { + ErrorCode errorCode = ErrorCode.UNKNOWN_ERROR; + if (t instanceof JifaException) { + errorCode = ((JifaException) t).getCode(); + } + + if (t instanceof IllegalArgumentException) { + errorCode = ErrorCode.ILLEGAL_ARGUMENT; + } + + if (errorCode == ErrorCode.ILLEGAL_ARGUMENT) { + return HTTP_BAD_REQUEST_STATUS_CODE; + } + return HTTP_INTERNAL_SERVER_ERROR_STATUS_CODE; + } + + private static void log(Throwable t) { + boolean shouldLogError = true; + + if (t instanceof JifaException) { + shouldLogError = ((JifaException) t).getCode().isFatal(); + } + + if (shouldLogError) { + LOGGER.error("Handle http request failed", t); + } + } + + private static int commonStatusCodeOf(HttpMethod method) { + if (method == HttpMethod.POST) { + return Constant.HTTP_POST_CREATED_STATUS_CODE; + } + return Constant.HTTP_GET_OK_STATUS_CODE; + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/util/PageViewBuilder.java b/backend/common/src/main/java/org/eclipse/jifa/common/util/PageViewBuilder.java new file mode 100644 index 0000000..b092347 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/util/PageViewBuilder.java
@@ -0,0 +1,67 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.util; + +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.vo.PageView; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PageViewBuilder { + + public static <S, R> PageView<R> build(Callback<S> callback, PagingRequest paging, Function<S, R> mapper) { + List<R> result = IntStream.range(paging.from(), paging.to(callback.totalSize())) + .mapToObj(callback::get) + .map(mapper) + .collect(Collectors.toList()); + return new PageView<>(paging, callback.totalSize(), result); + } + + public static <R> PageView<R> build(Collection<R> total, PagingRequest paging) { + List<R> result = total.stream() + .skip(paging.from()) + .limit(paging.getPageSize()) + .collect(Collectors.toList()); + return new PageView<>(paging, total.size(), result); + } + + public static <S, R> PageView<R> build(Collection<S> total, PagingRequest paging, Function<S, R> mapper) { + List<R> result = total.stream() + .skip(paging.from()) + .limit(paging.getPageSize()) + .map(mapper) + .collect(Collectors.toList()); + return new PageView<>(paging, total.size(), result); + } + + public static <R> PageView<R> build(int[] total, PagingRequest paging, IntFunction<R> mapper) { + List<R> result = Arrays.stream(total) + .skip(paging.from()) + .limit(paging.getPageSize()) + .mapToObj(mapper) + .collect(Collectors.toList()); + return new PageView<>(paging, total.length, result); + } + + public interface Callback<O> { + int totalSize(); + + O get(int index); + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/ErrorResult.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/ErrorResult.java new file mode 100644 index 0000000..dca44c1 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/ErrorResult.java
@@ -0,0 +1,46 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; + +@Data +public class ErrorResult { + + private ErrorCode errorCode = ErrorCode.UNKNOWN_ERROR; + + private String message; + + public ErrorResult(Throwable t) { + if (t instanceof JifaException) { + errorCode = ((JifaException) t).getCode(); + } + + if (t instanceof IllegalArgumentException) { + errorCode = ErrorCode.ILLEGAL_ARGUMENT; + } + + Throwable cause = t; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + + if (cause instanceof JifaException) { + message = cause.getMessage(); + } else { + message = cause.getClass().getSimpleName() + ": " + cause.getMessage(); + } + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/FileInfo.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/FileInfo.java new file mode 100644 index 0000000..16f3493 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/FileInfo.java
@@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; + +@Data +public class FileInfo { + + private String originalName; + + private String name; + + private long size; + + private FileType type; + + private ProgressState transferState; + + private boolean downloadable; + + private long creationTime; +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/PageView.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/PageView.java new file mode 100644 index 0000000..fc60688 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/PageView.java
@@ -0,0 +1,43 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import org.eclipse.jifa.common.request.PagingRequest; +import lombok.Data; + +import java.util.List; + +@Data +public class PageView<T> { + + private List<T> data; + + private int page; + + private int pageSize; + + private int totalSize; + + private int filtered; + + public PageView(PagingRequest request, int totalSize, List<T> data) { + this.data = data; + this.page = request.getPage(); + this.pageSize = request.getPageSize(); + this.totalSize = totalSize; + } + + public PageView() { + + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/Progress.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/Progress.java new file mode 100644 index 0000000..f9ad8ff --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/Progress.java
@@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; +import org.eclipse.jifa.common.enums.ProgressState; + +@Data +public class Progress { + + private ProgressState state; + + private double percent = 0; + + private String message; +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/Result.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/Result.java new file mode 100644 index 0000000..a16470f --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/Result.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; + +@Data +public class Result<R> { + + private R result; + + public Result(R result) { + this.result = result; + } +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferProgress.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferProgress.java new file mode 100644 index 0000000..29326f0 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferProgress.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class TransferProgress extends Progress { + + private long totalSize; + + private long transferredSize; +}
diff --git a/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferringFile.java b/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferringFile.java new file mode 100644 index 0000000..335a110 --- /dev/null +++ b/backend/common/src/main/java/org/eclipse/jifa/common/vo/TransferringFile.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.common.vo; + +import lombok.Data; + +@Data +public class TransferringFile { + + private String name; + + public TransferringFile(String fileName) { + this.name = fileName; + } +}
diff --git a/backend/worker/build.gradle b/backend/worker/build.gradle new file mode 100644 index 0000000..2d7626d --- /dev/null +++ b/backend/worker/build.gradle
@@ -0,0 +1,61 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +buildscript { + archivesBaseName = 'jifa-worker' +} + +plugins { + id 'application' +} + +distributions { + main { + baseName = 'jifa' + contents { + from("${project.rootDir}/build/static") { + into "webroot" + } + } + } +} + +dependencies { + compile project(':backend:common') + + compile group: 'io.vertx', name: 'vertx-core', version: "${vertx_version}" + compile group: 'io.vertx', name: 'vertx-config', version: "${vertx_version}" + compile group: 'io.vertx', name: 'vertx-web-client', version: "${vertx_version}" + + compile 'com.hierynomus:sshj:0.27.0' + + compile 'com.aliyun.oss:aliyun-sdk-oss:2.8.3' + + compile files("${project.rootDir}/mat.jar" as String) + + testCompile 'junit:junit:4.12' + testCompile group: 'io.vertx', name: 'vertx-unit', version: "${vertx_version}" + + runtimeOnly project(':frontend') +} + +compileJava { + targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +test { + useJUnit() +} + +mainClassName = 'org.eclipse.jifa.worker.Starter' +buildDir = "${project.rootDir}/build"
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/Constant.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/Constant.java new file mode 100644 index 0000000..483e696 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/Constant.java
@@ -0,0 +1,46 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker; + +public interface Constant extends org.eclipse.jifa.common.Constant { + + interface Misc { + String VERTX_CONFIG_KEY = "jifa.vertx.config"; + String WORKER_CONFIG_KEY = "jifa.worker.config"; + String DEFAULT_VERTX_CONFIG = "vertx-config.json"; + String DEFAULT_WORKER_CONFIG = "worker-config.json"; + + String DEFAULT_WORKSPACE = System.getProperty("user.home") + java.io.File.separator + "jifa_workspace"; + + String DEFAULT_HOST = "0.0.0.0"; + + String WEB_ROOT_KEY = "jifa.webroot"; + } + + interface Heap { + String TOTAL_SIZE_KEY = "totalSize"; + String SHALLOW_HEAP_KEY = "shallowHeap"; + String RETAINED_HEAP_KEY = "retainedHeap"; + } + + interface File { + String INFO_FILE_SUFFIX = "-info.json"; + } + + interface ConfigKey { + String WORKSPACE = "workspace"; + String API_PREFIX = "api.prefix"; + String SERVER_HOST_KEY = "server.host"; + String SERVER_PORT_KEY = "server.port"; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/Global.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/Global.java new file mode 100644 index 0000000..c7f8756 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/Global.java
@@ -0,0 +1,74 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker; + +import io.vertx.core.Vertx; +import io.vertx.core.json.JsonObject; +import org.eclipse.jifa.worker.support.FileSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +public class Global { + + private static final Logger LOGGER = LoggerFactory.getLogger(Starter.class); + + public static Vertx VERTX; + + public static String HOST; + + public static int PORT; + + private static JsonObject CONFIG; + + private static String WORKSPACE; + + private static boolean initialized; + + static synchronized void init(Vertx vertx, String host, int port, JsonObject config) { + if (initialized) { + return; + } + + VERTX = vertx; + HOST = host; + PORT = port; + CONFIG = config; + + WORKSPACE = CONFIG.getString(Constant.ConfigKey.WORKSPACE, Constant.Misc.DEFAULT_WORKSPACE); + LOGGER.debug("Workspace: {}", WORKSPACE); + + File workspaceDir = new File(WORKSPACE); + if (workspaceDir.exists()) { + ASSERT.isTrue(workspaceDir.isDirectory(), "Workspace must be directory"); + } else { + ASSERT.isTrue(workspaceDir.mkdirs(), + () -> "Can not create workspace: " + workspaceDir.getAbsolutePath()); + } + + FileSupport.init(); + + initialized = true; + } + + public static String stringConfig(String key) { + return CONFIG.getString(key); + } + + public static String workspace() { + return WORKSPACE; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/Starter.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/Starter.java new file mode 100644 index 0000000..fe07a83 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/Starter.java
@@ -0,0 +1,130 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker; + +import com.google.common.base.Strings; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.DeploymentOptions; +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.core.http.HttpServer; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import io.vertx.ext.web.handler.CorsHandler; +import io.vertx.ext.web.handler.StaticHandler; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.eclipse.jifa.worker.route.RouteFiller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; +import java.nio.charset.Charset; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; + +import static org.eclipse.jifa.worker.Constant.ConfigKey.SERVER_HOST_KEY; +import static org.eclipse.jifa.worker.Constant.ConfigKey.SERVER_PORT_KEY; +import static org.eclipse.jifa.worker.Constant.Misc.*; + +public class Starter extends AbstractVerticle { + + private static final Logger LOGGER = LoggerFactory.getLogger(Starter.class); + + private static CountDownLatch count; + + public static void main(String[] args) throws Exception { + long start = System.currentTimeMillis(); + + JsonObject vc = new JsonObject(readConfig(VERTX_CONFIG_KEY, DEFAULT_VERTX_CONFIG)); + Vertx vertx = Vertx.vertx(new VertxOptions(vc)); + JsonObject wc = new JsonObject(readConfig(WORKER_CONFIG_KEY, DEFAULT_WORKER_CONFIG)); + int processors = Runtime.getRuntime().availableProcessors(); + + count = new CountDownLatch(processors); + vertx.deployVerticle(Starter.class.getName(), new DeploymentOptions().setConfig(wc).setInstances(processors)); + count.await(); + + LOGGER.info("Jifa-Worker startup successfully in {} ms, verticle count = {}, http server = {}:{}", + System.currentTimeMillis() - start, processors, Global.HOST, Global.PORT); + } + + private static String readConfig(String key, String def) throws IOException { + String v = System.getProperty(key); + return Strings.isNullOrEmpty(v) + ? IOUtils.toString(Objects.requireNonNull(Starter.class.getClassLoader().getResource(def)), + Charset.defaultCharset()) + : FileUtils.readFileToString(new File(v), Charset.defaultCharset()); + } + + private static int randomPort() { + try { + ServerSocket socket = new ServerSocket(0); + int port = socket.getLocalPort(); + socket.close(); + return port; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void start() { + String host = config().containsKey(SERVER_HOST_KEY) ? config().getString(SERVER_HOST_KEY) : DEFAULT_HOST; + + int port = config().containsKey(SERVER_PORT_KEY) ? config().getInteger(SERVER_PORT_KEY) : randomPort(); + + String staticRoot = System.getProperty(WEB_ROOT_KEY, "webroot"); + + vertx.executeBlocking(event -> { + Global.init(vertx, host, port, config()); + + HttpServer server = vertx.createHttpServer(); + Router router = Router.router(vertx); + + File webRoot = new File(staticRoot); + if (webRoot.exists() && webRoot.isDirectory()) { + String staticPattern = "^(?!" + Global.stringConfig(Constant.ConfigKey.API_PREFIX) + ").*$"; + StaticHandler staticHandler = StaticHandler.create(); + staticHandler.setAllowRootFileSystemAccess(true); + staticHandler.setWebRoot(staticRoot); + router.routeWithRegex(staticPattern).handler(staticHandler); + } + // cors + router.route().handler(CorsHandler.create("*")); + router.post().handler(BodyHandler.create()); + + new RouteFiller(router).fill(); + server.requestHandler(router); + + server.listen(port, host, ar -> { + if (ar.succeeded()) { + event.complete(); + } else { + event.fail(ar.cause()); + } + }); + }, ar -> { + if (ar.succeeded()) { + count.countDown(); + } else { + LOGGER.error("Worker-Verticle startup failed", ar.cause()); + System.exit(-1); + } + }); + } + +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/AnalysisRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/AnalysisRoute.java new file mode 100644 index 0000000..4fefaf2 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/AnalysisRoute.java
@@ -0,0 +1,78 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import org.eclipse.jifa.worker.Constant; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.vo.Progress; +import org.eclipse.jifa.common.vo.Result; +import org.eclipse.jifa.common.util.FileUtil; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.FileSupport; +import io.vertx.core.Future; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Map; + +@MappingPrefix(value = {"/heap-dump/:file"}) +class AnalysisRoute extends BaseRoute { + private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisRoute.class); + private Analyzer helper = Analyzer.getInstance(); + + // TODO: not good enough + private FileType typeOf(HttpServerRequest request) { + String uri = request.uri(); + String apiPrefix = Global.stringConfig(Constant.ConfigKey.API_PREFIX); + int end = uri.indexOf("/", apiPrefix.length() + 1); + return FileType.getByTag(uri.substring(apiPrefix.length() + 1, end)); + } + + @RouteMeta(path = "/isFirstAnalysis") + void isFirstAnalysis(HttpServerRequest request, Future<Result<Boolean>> future, @ParamKey("file") String file) { + future.complete(new Result<>(helper.isFirstAnalysis(typeOf(request), file))); + } + + @RouteMeta(path = "/analyze", method = HttpMethod.POST) + void analyze(HttpServerRequest request, Future<Void> future, @ParamKey("file") String file, + @ParamMap(keys = {"keep_unreachable_objects", "heap_layout"}, + mandatory = {false, false}) Map<String, String> options) { + helper.analyze(future, typeOf(request), file, options); + } + + @RouteMeta(path = "/progressOfAnalysis") + void poll(HttpServerRequest request, Future<Progress> future, @ParamKey("file") String file) { + future.complete(helper.pollProgress(typeOf(request), file)); + } + + @RouteMeta(path = "/release", method = HttpMethod.POST) + void release(HttpServerRequest request, Future<Void> future, @ParamKey("file") String file) { + helper.release(file); + future.complete(); + } + + @RouteMeta(path = "/clean", method = HttpMethod.POST) + void clean(HttpServerRequest request, Future<Void> future, @ParamKey("file") String file) { + helper.clean(typeOf(request), file); + future.complete(); + } + + @RouteMeta(path = "/errorLog") + void failedLog(HttpServerRequest request, Future<Result<String>> future, @ParamKey("file") String file) { + future.complete(new Result<>(FileUtil.content(new File(FileSupport.errorLogPath(typeOf(request), file))))); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/BaseRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/BaseRoute.java new file mode 100644 index 0000000..515da46 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/BaseRoute.java
@@ -0,0 +1,16 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +public abstract class BaseRoute { +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/FileRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/FileRoute.java new file mode 100644 index 0000000..db7a4b0 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/FileRoute.java
@@ -0,0 +1,226 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import io.vertx.core.Future; +import io.vertx.core.file.FileSystem; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.FileUpload; +import io.vertx.ext.web.RoutingContext; +import org.apache.logging.log4j.util.Strings; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.HTTPRespGuarder; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.FileInfo; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.vo.TransferProgress; +import org.eclipse.jifa.common.vo.TransferringFile; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.worker.support.FileSupport; +import org.eclipse.jifa.worker.support.heapdump.TransferListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.List; +import java.util.Set; + +import static org.eclipse.jifa.common.Constant.EMPTY_STRING; +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class FileRoute extends BaseRoute { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileRoute.class); + + @RouteMeta(path = "/files") + void list(Future<PageView<FileInfo>> future, @ParamKey("type") FileType type, PagingRequest paging) { + List<FileInfo> info = FileSupport.info(type); + info.sort((i1, i2) -> Long.compare(i2.getCreationTime(), i1.getCreationTime())); + future.complete(PageViewBuilder.build(info, paging)); + } + + @RouteMeta(path = "/file") + void file(Future<FileInfo> future, @ParamKey("type") FileType type, @ParamKey("name") String name) { + future.complete(FileSupport.info(type, name)); + } + + @RouteMeta(path = "/file/delete", method = HttpMethod.POST) + void delete(Future<Void> future, @ParamKey("type") FileType type, @ParamKey("name") String name) { + FileSupport.delete(type, name); + future.complete(); + } + + @RouteMeta(path = "/publicKey") + void publicKeys(Future<String> future) { + if (FileSupport.PUB_KEYS.size() > 0) { + future.complete(FileSupport.PUB_KEYS.get(0)); + } else { + future.complete(EMPTY_STRING); + } + } + + private String decorateFileName(String fileName) { + return System.currentTimeMillis() + "-" + fileName; + } + + private String extractFileName(String path) { + return path.substring(path.lastIndexOf(File.separatorChar) + 1); + } + + @RouteMeta(path = "/file/transferByURL", method = HttpMethod.POST) + void transferByURL(Future<TransferringFile> future, @ParamKey("type") FileType fileType, + @ParamKey("url") String url, @ParamKey(value = "fileName", mandatory = false) String fileName) { + + String originalName = extractFileName(url); + + fileName = Strings.isNotBlank(fileName) ? fileName : decorateFileName(originalName); + + TransferListener listener = FileSupport.createTransferListener(fileType, originalName, fileName); + + FileSupport.transferByURL(url, fileType, fileName, listener, future); + } + + @RouteMeta(path = "/file/transferByOSS", method = HttpMethod.POST) + void transferByOSS(Future<TransferringFile> future, @ParamKey("type") FileType fileType, + @ParamKey("endpoint") String endpoint, @ParamKey("accessKeyId") String accessKeyId, + @ParamKey("accessKeySecret") String accessKeySecret, @ParamKey("bucketName") String bucketName, + @ParamKey("objectName") String objectName, + @ParamKey(value = "fileName", mandatory = false) String fileName) { + + String originalName = extractFileName(objectName); + fileName = Strings.isNotBlank(fileName) ? fileName : decorateFileName(originalName); + + TransferListener listener = FileSupport.createTransferListener(fileType, originalName, fileName); + + FileSupport.transferByOSS(endpoint, accessKeyId, accessKeySecret, bucketName, objectName, + fileType, fileName, listener, future); + } + + @RouteMeta(path = "/file/transferBySCP", method = HttpMethod.POST) + void transferBySCP(Future<TransferringFile> future, @ParamKey("type") FileType fileType, + @ParamKey("hostname") String hostname, @ParamKey("path") String path, + @ParamKey("user") String user, @ParamKey("usePublicKey") boolean usePublicKey, + @ParamKey(value = "password", mandatory = false) String password, + @ParamKey(value = "fileName", mandatory = false) String fileName) { + + if (!usePublicKey) { + ASSERT.isTrue(password != null && password.length() > 0, + "Must provide password if you don't use public key"); + } + + String originalName = extractFileName(path); + fileName = Strings.isNotBlank(fileName) ? fileName : decorateFileName(extractFileName(path)); + TransferListener listener = FileSupport.createTransferListener(fileType, originalName, fileName); + // do transfer + if (usePublicKey) { + FileSupport.transferBySCP(user, hostname, path, fileType, fileName, listener, future); + } else { + FileSupport.transferBySCP(user, password, hostname, path, fileType, fileName, listener, future); + } + } + + @RouteMeta(path = "/file/transferByFileSystem", method = HttpMethod.POST) + void transferByFileSystem(Future<TransferringFile> future, @ParamKey("type") FileType fileType, + @ParamKey("path") String path, @ParamKey("move") boolean move) { + File src = new File(path); + ASSERT.isTrue(src.exists() && !src.isDirectory(), "Illegal path"); + + String originalName = extractFileName(path); + String fileName = decorateFileName(originalName); + + future.complete(new TransferringFile(fileName)); + TransferListener listener = FileSupport.createTransferListener(fileType, originalName, fileName); + + listener.setTotalSize(src.length()); + listener.updateState(ProgressState.IN_PROGRESS); + if (move) { + Global.VERTX.fileSystem().moveBlocking(path, FileSupport.filePath(fileType, fileName)); + } else { + Global.VERTX.fileSystem().copyBlocking(path, FileSupport.filePath(fileType, fileName)); + } + listener.setTransferredSize(listener.getTotalSize()); + listener.updateState(ProgressState.SUCCESS); + } + + @RouteMeta(path = "/file/transferProgress") + void transferProgress(Future<TransferProgress> future, @ParamKey("type") FileType type, + @ParamKey("name") String name) { + TransferListener listener = FileSupport.getTransferListener(name); + if (listener != null) { + TransferProgress progress = new TransferProgress(); + progress.setTotalSize(listener.getTotalSize()); + progress.setTransferredSize(listener.getTransferredSize()); + progress.setMessage(listener.getErrorMsg()); + if (listener.getTotalSize() > 0) { + progress.setPercent((double) listener.getTransferredSize() / (double) listener.getTotalSize()); + } + progress.setState(listener.getState()); + + if (progress.getState() == ProgressState.SUCCESS || progress.getState() == ProgressState.ERROR) { + FileSupport.removeTransferListener(name); + } + future.complete(progress); + } else { + FileInfo info = FileSupport.info(type, name); + ASSERT.notNull(info); + if (info.getTransferState() == ProgressState.IN_PROGRESS + || info.getTransferState() == ProgressState.NOT_STARTED) { + LOGGER.warn("Illegal file {} state", name); + info.setTransferState(ProgressState.ERROR); + FileSupport.save(info); + } + TransferProgress progress = new TransferProgress(); + progress.setState(info.getTransferState()); + if (progress.getState() == ProgressState.SUCCESS) { + progress.setPercent(1.0); + progress.setTotalSize(info.getSize()); + progress.setTransferredSize(info.getSize()); + } + future.complete(progress); + } + } + + @RouteMeta(path = "/file/upload", method = HttpMethod.POST) + void upload(RoutingContext context, @ParamKey("type") FileType type) { + Set<FileUpload> fileUploads = context.fileUploads(); + for (FileUpload upload : fileUploads) { + String fileName = decorateFileName(upload.fileName()); + FileSupport.initInfoFile(type, upload.fileName(), fileName); + FileSystem fileSystem = context.vertx().fileSystem(); + fileSystem.moveBlocking(upload.uploadedFileName(), FileSupport.filePath(type, fileName)); + FileSupport.updateTransferState(type, fileName, ProgressState.SUCCESS); + } + HTTPRespGuarder.ok(context); + } + + @RouteMeta(path = "/file/download/:fileType/:filename", contentType = {} /* keep content-type empty */) + void download(RoutingContext context, @ParamKey("fileType") FileType fileType, @ParamKey("filename") String name) { + File file = new File(FileSupport.filePath(fileType, name)); + ASSERT.isTrue(file.exists(), "File doesn't exist!"); + HttpServerResponse response = context.response(); + response.sendFile(file.getAbsolutePath(), event -> { + if (!response.ended()) { + response.end(); + } + }); + } + + @RouteMeta(path = "/file/getOrGenInfo", method = HttpMethod.POST) + void getOrGenInfo(Future<FileInfo> future, @ParamKey("fileType") FileType fileType, + @ParamKey("filename") String name) { + future.complete(FileSupport.getOrGenInfo(fileType, name)); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/MappingPrefix.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/MappingPrefix.java new file mode 100644 index 0000000..882a0fd --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/MappingPrefix.java
@@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MappingPrefix { + String[] value() default ""; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamKey.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamKey.java new file mode 100644 index 0000000..2793eb1 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamKey.java
@@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface ParamKey { + + String value(); + + boolean mandatory() default true; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamMap.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamMap.java new file mode 100644 index 0000000..ad9601c --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/ParamMap.java
@@ -0,0 +1,28 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; + +@Retention(RetentionPolicy.RUNTIME) +@Target(PARAMETER) +public @interface ParamMap { + + String[] keys(); + + boolean[] mandatory(); +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteFiller.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteFiller.java new file mode 100644 index 0000000..afca782 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteFiller.java
@@ -0,0 +1,135 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import io.vertx.ext.web.Route; +import io.vertx.ext.web.Router; +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.util.HTTPRespGuarder; +import org.eclipse.jifa.worker.Constant; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.worker.route.heapdump.HeapBaseRoute; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class RouteFiller { + + private static final Logger LOGGER = LoggerFactory.getLogger(RouteFiller.class); + + private Router router; + + public RouteFiller(Router router) { + this.router = router; + } + + public void fill() { + try { + register(FileRoute.class); + register(AnalysisRoute.class); + + for (Class<? extends HeapBaseRoute> route : HeapBaseRoute.routes()) { + register(route); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String[] buildPrefixes(Class<?> clazz) { + ArrayList<String> prefixes = new ArrayList<>(); + buildPrefix(prefixes, "", clazz); + return prefixes.toArray(new String[0]); + } + + private void buildPrefix(ArrayList<String> prefixes, String prevPrefix, Class<?> clazz) { + if (clazz == null) { + String rootPrefix = Global.stringConfig(Constant.ConfigKey.API_PREFIX); + prefixes.add(rootPrefix + prevPrefix); + return; + } + + MappingPrefix anno = clazz.getDeclaredAnnotation(MappingPrefix.class); + if (anno == null) { + buildPrefix(prefixes, prevPrefix, clazz.getSuperclass()); + } else { + for (int i = 0; i < anno.value().length; i++) { + buildPrefix(prefixes, anno.value()[i] + prevPrefix, clazz.getSuperclass()); + } + } + } + + private void register(Class<? extends BaseRoute> clazz) throws Exception { + Constructor<? extends BaseRoute> constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + BaseRoute thisObject = constructor.newInstance(); + + String[] prefixes = buildPrefixes(clazz); + Method[] methods = clazz.getDeclaredMethods(); + for (String prefix : prefixes) { + for (Method method : methods) { + registerMethodRoute(thisObject, prefix, method); + } + } + } + + private void registerMethodRoute(BaseRoute thisObject, String prefix, Method method) { + RouteMeta meta = method.getAnnotation(RouteMeta.class); + if (meta == null) { + return; + } + + String fullPath = prefix + meta.path(); + Route route = router.route(meta.method(), fullPath); + Arrays.stream(meta.contentType()).forEach(route::produces); + method.setAccessible(true); + + LOGGER.debug("Route: path = {}, method = {}", fullPath, method.toGenericString()); + + route.blockingHandler(rc -> { + try { + // pre-process + if (meta.contentType().length > 0) { + rc.response().putHeader("content-type", String.join(";", meta.contentType())); + } + + List<Object> arguments = new ArrayList<>(); + Parameter[] params = method.getParameters(); + for (Parameter param : params) { + if (!RouterAnnotationProcessor.processParamKey(arguments, rc, method, param) && + !RouterAnnotationProcessor.processParamMap(arguments, rc, method, param) && + !RouterAnnotationProcessor.processPagingRequest(arguments, rc, method, param) && + !RouterAnnotationProcessor.processHttpServletRequest(arguments, rc, method, param) && + !RouterAnnotationProcessor.processHttpServletResponse(arguments, rc, method, param) && + !RouterAnnotationProcessor.processFuture(arguments, rc, method, param) && + !RouterAnnotationProcessor.processRoutingContext(arguments, rc, method, param) + ) { + throw new JifaException(ErrorCode.ILLEGAL_ARGUMENT, + "Illegal parameter meta, method = " + method); + } + + } + method.invoke(thisObject, arguments.toArray()); + } catch (Throwable t) { + HTTPRespGuarder.fail(rc, t); + } + }, false); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteMeta.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteMeta.java new file mode 100644 index 0000000..be764c7 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouteMeta.java
@@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import io.vertx.core.http.HttpMethod; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RouteMeta { + + HttpMethod method() default HttpMethod.GET; + + String path(); + + String[] contentType() default {"application/json; charset=utf-8"}; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouterAnnotationProcessor.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouterAnnotationProcessor.java new file mode 100644 index 0000000..2ef1185 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/RouterAnnotationProcessor.java
@@ -0,0 +1,171 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import com.google.gson.Gson; +import io.vertx.core.Future; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.HTTPRespGuarder; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class RouterAnnotationProcessor { + private static Map<Class<?>, Function<String, ?>> converter = new HashMap<>(); + + static { + converter.put(String.class, s -> s); + converter.put(Integer.class, Integer::parseInt); + converter.put(int.class, Integer::parseInt); + converter.put(Long.class, Long::parseLong); + converter.put(long.class, Long::parseLong); + converter.put(Float.class, Float::parseFloat); + converter.put(float.class, Float::parseFloat); + converter.put(Double.class, Double::parseDouble); + converter.put(double.class, Double::parseDouble); + converter.put(Boolean.class, Boolean::parseBoolean); + converter.put(boolean.class, Boolean::parseBoolean); + converter.put(int[].class, s -> new Gson().fromJson(s, int[].class)); + } + + static boolean processParamKey(List<Object> arguments, RoutingContext context, Method method, Parameter param) { + // param key + ParamKey paramKey = param.getAnnotation(ParamKey.class); + if (paramKey != null) { + String value = context.request().getParam(paramKey.value()); + ASSERT.isTrue(!paramKey.mandatory() || value != null, ErrorCode.ILLEGAL_ARGUMENT, + () -> "Miss request parameter, key = " + paramKey.value()); + arguments.add(value != null ? convert(method, param, context.request().getParam(paramKey.value())) : null); + return true; + } + return false; + } + + static boolean processParamMap(List<Object> arguments, RoutingContext context, Method method, Parameter param) { + ParamMap paramMap = param.getAnnotation(ParamMap.class); + if (paramMap != null) { + Map<String, String> map = new HashMap<>(); + String[] keys = paramMap.keys(); + boolean[] mandatory = paramMap.mandatory(); + for (int j = 0; j < keys.length; j++) { + String key = keys[j]; + String value = context.request().getParam(key); + ASSERT.isTrue(!mandatory[j] || value != null, ErrorCode.ILLEGAL_ARGUMENT, + () -> "Miss request parameter, key = " + key); + if (value != null) { + map.put(key, value); + } + } + arguments.add(map); + return true; + } + return false; + } + + static boolean processPagingRequest(List<Object> arguments, RoutingContext context, Method method, + Parameter param) { + if (param.getType() == PagingRequest.class) { + int page; + int pageSize; + try { + page = Integer.parseInt(context.request().getParam("page")); + pageSize = Integer.parseInt(context.request().getParam("pageSize")); + ASSERT.isTrue(page >= 1 && pageSize >= 1, ErrorCode.ILLEGAL_ARGUMENT, + "must greater than 1"); + } catch (Exception e) { + throw new JifaException(ErrorCode.ILLEGAL_ARGUMENT, "Paging parameter(page or pageSize) is illegal, " + + e.getMessage()); + } + arguments.add(new PagingRequest(page, pageSize)); + return true; + } + return false; + } + + static boolean processHttpServletRequest(List<Object> arguments, RoutingContext context, Method method, + Parameter param) { + if (param.getType().equals(HttpServerRequest.class)) { + arguments.add(context.request()); + return true; + } + return false; + } + + static boolean processHttpServletResponse(List<Object> arguments, RoutingContext context, Method method, + Parameter param) { + if (param.getType().equals(HttpServerResponse.class)) { + arguments.add(context.response()); + return true; + } + return false; + } + + static boolean processFuture(List<Object> arguments, RoutingContext context, Method method, Parameter param) { + if (param.getType().equals(Future.class)) { + arguments.add(newFuture(context)); + return true; + } + return false; + } + + static boolean processRoutingContext(List<Object> arguments, RoutingContext context, Method method, Parameter param) { + if (param.getType().equals(RoutingContext.class)) { + arguments.add(context); + return true; + } + return false; + } + + private static Object convert(Method m, Parameter p, String value) { + Class<?> type = p.getType(); + Function<String, ?> f; + if (type.isEnum()) { + f = s -> { + for (Object e : type.getEnumConstants()) { + if (((Enum) e).name().equalsIgnoreCase(value)) { + return e; + } + } + throw new JifaException(ErrorCode.ILLEGAL_ARGUMENT, + "Illegal parameter value, parameter = " + p + ", value = " + value); + }; + } else { + f = converter.get(type); + } + ASSERT.notNull(f, () -> "Unsupported parameter type, method = " + m + ", parameter = " + p); + return f.apply(value); + } + + private static <T> Future<T> newFuture(io.vertx.ext.web.RoutingContext rc) { + Future<T> future = Future.future(); + future.setHandler(event -> { + if (event.succeeded()) { + HTTPRespGuarder.ok(rc, event.result()); + } else { + HTTPRespGuarder.fail(rc, event.cause()); + } + }); + return future; + } +} \ No newline at end of file
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassLoaderRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassLoaderRoute.java new file mode 100644 index 0000000..9c0dd8f --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassLoaderRoute.java
@@ -0,0 +1,115 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import io.vertx.core.Future; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.SnapshotContext; +import org.eclipse.jifa.worker.vo.heapdump.classloader.Record; +import org.eclipse.jifa.worker.vo.heapdump.classloader.Summary; +import org.eclipse.mat.query.IDecorator; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.query.IStructuredResult; +import org.eclipse.mat.snapshot.model.IClass; + +import java.lang.reflect.Field; +import java.util.Map; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class ClassLoaderRoute extends HeapBaseRoute { + + private static final Field NODE_PARENT_FIELD; + private static final Field PARENT_NODE_FIELD; + + static { + try { + NODE_PARENT_FIELD = + Class.forName("org.eclipse.mat.inspections.ClassLoaderExplorerQuery$Node").getDeclaredField("parent"); + NODE_PARENT_FIELD.setAccessible(true); + + PARENT_NODE_FIELD = + Class.forName("org.eclipse.mat.inspections.ClassLoaderExplorerQuery$Parent").getDeclaredField("node"); + PARENT_NODE_FIELD.setAccessible(true); + } catch (Exception e) { + throw new JifaException(e); + } + } + + @RouteMeta(path = "/classLoaderExplorer/summary") + void summary(Future<Summary> future, @ParamKey("file") String file) throws Exception { + + SnapshotContext.ClassLoaderExplorer explorer = Analyzer.getOrOpenSnapshotContext(file).classLoaderExplorer(); + Summary summary = new Summary(); + summary.setTotalSize(explorer.getRecords().size()); + summary.setDefinedClasses(explorer.getDefinedClasses()); + summary.setNumberOfInstances(explorer.getNumberOfInstances()); + future.complete(summary); + } + + @RouteMeta(path = "/classLoaderExplorer/classLoader") + void classLoaders(Future<PageView<Record>> future, @ParamKey("file") String file, + PagingRequest pagingRequest) throws Exception { + SnapshotContext.ClassLoaderExplorer explorer = Analyzer.getOrOpenSnapshotContext(file).classLoaderExplorer(); + IStructuredResult resultContext = (IStructuredResult) explorer.getResultContext(); + future.complete(PageViewBuilder.build(explorer.getRecords(), pagingRequest, e -> { + try { + Record r = new Record(); + r.setObjectId(resultContext.getContext(e).getObjectId()); + r.setPrefix(((IDecorator) resultContext).prefix(e)); + r.setLabel((String) resultContext.getColumnValue(e, 0)); + r.setDefinedClasses((Integer) resultContext.getColumnValue(e, 1)); + r.setNumberOfInstances((Integer) resultContext.getColumnValue(e, 2)); + r.setClassLoader(true); + r.setHasParent(NODE_PARENT_FIELD.get(e) != null); + return r; + } catch (Exception ex) { + throw new JifaException(ex); + } + })); + } + + @RouteMeta(path = "/classLoaderExplorer/children") + void children(Future<PageView<Record>> future, @ParamKey("file") String file, + @ParamKey("classLoaderId") int classLoaderId, PagingRequest pagingRequest) throws Exception { + + SnapshotContext.ClassLoaderExplorer explorer = Analyzer.getOrOpenSnapshotContext(file).classLoaderExplorer(); + IResultTree resultContext = (IResultTree) explorer.getResultContext(); + Map<Integer, Object> classLoaderIdMap = explorer.getClassLoaderIdMap(); + Object classLoaderNode = classLoaderIdMap.get(classLoaderId); + ASSERT.notNull(classLoaderNode, "Illegal classLoaderId"); + future.complete(PageViewBuilder.build(resultContext.getChildren(classLoaderNode), pagingRequest, e -> { + try { + Record r = new Record(); + r.setObjectId(resultContext.getContext(e).getObjectId()); + r.setPrefix(((IDecorator) resultContext).prefix(e)); + r.setLabel((String) resultContext.getColumnValue(e, 0)); + r.setNumberOfInstances((Integer) resultContext.getColumnValue(e, 2)); + if (!(e instanceof IClass)) { + r.setClassLoader(true); + r.setDefinedClasses((Integer) resultContext.getColumnValue(e, 1)); + r.setHasParent(NODE_PARENT_FIELD.get(PARENT_NODE_FIELD.get(e)) != null); + } + return r; + } catch (Exception ex) { + throw new JifaException(ex); + } + })); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassReferenceRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassReferenceRoute.java new file mode 100644 index 0000000..996f77e --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ClassReferenceRoute.java
@@ -0,0 +1,111 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import io.vertx.core.Future; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.classreference.Record; +import org.eclipse.mat.inspections.ClassReferrersQuery; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.query.IContextObjectSet; +import org.eclipse.mat.query.IIconProvider; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.query.Icons; + +import java.net.URL; + +class ClassReferenceRoute extends HeapBaseRoute { + + private static int getType(URL icon) { + if (icon == Icons.CLASS_IN || icon == Icons.CLASS_OUT) { + return ClassReferrersQuery.Type.NEW; + } else if (icon == Icons.CLASS_IN_MIXED || icon == Icons.CLASS_OUT_MIXED) { + return ClassReferrersQuery.Type.MIXED; + } else if (icon == Icons.CLASS_IN_OLD || icon == Icons.CLASS_OUT_OLD) { + return ClassReferrersQuery.Type.OLD_FAD; + } + throw new JifaException(); + } + + private static Record build(IResultTree result, Object row) { + Record record = new Record(); + record.setLabel((String) result.getColumnValue(row, 0)); + record.setObjects((Integer) result.getColumnValue(row, 1)); + record.setShallowSize(((Bytes) result.getColumnValue(row, 2)).getValue()); + IContextObjectSet context = (IContextObjectSet) result.getContext(row); + record.setObjectId(context.getObjectId()); + record.setObjectIds(context.getObjectIds()); + record.setType(getType(((IIconProvider) result).getIcon(row))); + return record; + + } + + private void process(Future<Object> future, String file, int objectId, boolean inbound) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + ClassReferrersQuery query = new ClassReferrersQuery(); + query.snapshot = snapshot; + query.objects = HeapDumpSupport.buildHeapObjectArgument(new int[]{objectId}); + query.inbound = inbound; + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + + Object node = result.getElements().get(0); + future.complete(build(result, node)); + } + + private void process(Future<Object> future, String file, PagingRequest pagingRequest, int[] objectIds, + boolean inbound) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + ClassReferrersQuery query = new ClassReferrersQuery(); + query.snapshot = snapshot; + query.objects = HeapDumpSupport.buildHeapObjectArgument(objectIds); + query.inbound = inbound; + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + + Object node = result.getElements().get(0); + future.complete(PageViewBuilder.build(result.getChildren(node), pagingRequest, e -> build(result, e))); + } + + @RouteMeta(path = "/classReference/inbounds/class") + void inboundsClassInfo(Future<Object> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws Exception { + + process(future, file, objectId, true); + } + + @RouteMeta(path = "/classReference/outbounds/class") + void outboundsClassInfo(Future<Object> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws Exception { + + process(future, file, objectId, false); + } + + @RouteMeta(path = "/classReference/inbounds/children") + void inboundsChildren(Future<Object> future, @ParamKey("file") String file, PagingRequest pagingRequest, + @ParamKey("objectIds") int[] objectIds) throws Exception { + process(future, file, pagingRequest, objectIds, true); + } + + @RouteMeta(path = "/classReference/outbounds/children") + void outboundsChildren(Future<Object> future, @ParamKey("file") String file, PagingRequest pagingRequest, + @ParamKey("objectIds") int[] objectIds) throws Exception { + process(future, file, pagingRequest, objectIds, false); + } + +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/CompareRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/CompareRoute.java new file mode 100644 index 0000000..aedd325 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/CompareRoute.java
@@ -0,0 +1,94 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import io.vertx.core.Future; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.FileInfo; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.FileSupport; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.compare.Record; +import org.eclipse.jifa.worker.vo.heapdump.compare.Summary; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.snapshot.Histogram; +import org.eclipse.mat.snapshot.ISnapshot; + +import java.util.List; +import java.util.stream.Collectors; + +class CompareRoute extends HeapBaseRoute { + + @RouteMeta(path = "/compare/files") + void files(Future<PageView<FileInfo>> future, @ParamKey("file") String source, + @ParamKey(value = "expected", mandatory = false) String expected, PagingRequest pagingRequest) { + future.complete(PageViewBuilder.build(FileSupport.info(FileType.HEAP_DUMP).stream().filter( + fileInfo -> !fileInfo.getName().equals(source) && fileInfo.getTransferState() == ProgressState.SUCCESS) + .sorted((i1, i2) -> Long + .compare(i2.getCreationTime(), i1.getCreationTime())) + .collect(Collectors.toList()), pagingRequest)); + } + + @RouteMeta(path = "/compare/summary") + void summary(Future<Summary> future, @ParamKey("file") String target, + @ParamKey("baseline") String baseline) throws Exception { + + ISnapshot targetSnapshot = Analyzer.getOrOpenSnapshotContext(target).getSnapshot(); + ISnapshot baselineSnapshot = Analyzer.getOrOpenSnapshotContext(baseline).getSnapshot(); + Histogram targetHistogram = targetSnapshot.getHistogram(HeapDumpSupport.VOID_LISTENER); + Histogram baselineHistogram = baselineSnapshot.getHistogram(HeapDumpSupport.VOID_LISTENER); + final Histogram delta = targetHistogram.diffWithBaseline(baselineHistogram); + + long totalObjects = 0; + long totalShallowHeap = 0; + for (Object r : delta.getClassHistogramRecords()) { + totalObjects += (long) delta.getColumnValue(r, 1); + totalShallowHeap += ((Bytes) delta.getColumnValue(r, 2)).getValue(); + } + + Summary summary = new Summary(); + summary.setTotalSize(delta.getClassHistogramRecords().size()); + summary.setObjects(totalObjects); + summary.setShallowSize(totalShallowHeap); + future.complete(summary); + } + + @SuppressWarnings("unchecked") + @RouteMeta(path = "/compare/records") + void record(Future<PageView<Record>> future, @ParamKey("file") String target, @ParamKey("baseline") String baseline, + PagingRequest pagingRequest) throws Exception { + + ISnapshot targetSnapshot = Analyzer.getOrOpenSnapshotContext(target).getSnapshot(); + ISnapshot baselineSnapshot = Analyzer.getOrOpenSnapshotContext(baseline).getSnapshot(); + Histogram targetHistogram = targetSnapshot.getHistogram(HeapDumpSupport.VOID_LISTENER); + Histogram baselineHistogram = baselineSnapshot.getHistogram(HeapDumpSupport.VOID_LISTENER); + final Histogram delta = targetHistogram.diffWithBaseline(baselineHistogram); + ((List) delta.getClassHistogramRecords()).sort((o1, o2) -> Long + .compare(((Bytes) delta.getColumnValue(o2, 2)).getValue(), + ((Bytes) delta.getColumnValue(o1, 2)).getValue())); + + future.complete(PageViewBuilder.build(delta.getClassHistogramRecords(), pagingRequest, r -> { + Record record = new Record(); + record.setClassName((String) delta.getColumnValue(r, 0)); + record.setObjects((Long) delta.getColumnValue(r, 1)); + record.setShallowSize(((Bytes) delta.getColumnValue(r, 2)).getValue()); + return record; + })); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DirectByteBufferRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DirectByteBufferRoute.java new file mode 100644 index 0000000..5e2ae79 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DirectByteBufferRoute.java
@@ -0,0 +1,69 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.SnapshotContext; +import org.eclipse.jifa.worker.vo.heapdump.directbytebuffer.Record; +import org.eclipse.jifa.worker.vo.heapdump.directbytebuffer.Summary; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import io.vertx.core.Future; +import org.eclipse.mat.query.IResultTable; + +class DirectByteBufferRoute extends HeapBaseRoute { + + @RouteMeta(path = "/directByteBuffer/summary") + void summary(Future<Summary> future, @ParamKey("file") String file) throws Exception { + + SnapshotContext.DirectByteBuffer data = Analyzer.getOrOpenSnapshotContext(file).directByteBuffer(); + + Summary summary = new Summary(); + summary.setTotalSize(data.getTotalSize()); + summary.setPosition(data.getPosition()); + summary.setLimit(data.getLimit()); + summary.setCapacity(data.getCapacity()); + future.complete(summary); + } + + @RouteMeta(path = "/directByteBuffer/records") + void record(Future<PageView<Record>> future, @ParamKey("file") String file, + PagingRequest pagingRequest) throws Exception { + + SnapshotContext.DirectByteBuffer data = Analyzer.getOrOpenSnapshotContext(file).directByteBuffer(); + IResultTable resultContext = data.getResultContext(); + + future.complete(PageViewBuilder.build(new PageViewBuilder.Callback<Object>() { + @Override + public int totalSize() { + return data.getTotalSize(); + } + + @Override + public Object get(int index) { + return data.getResultContext().getRow(index); + } + }, pagingRequest, row -> { + Record record = new Record(); + record.setObjectId(resultContext.getContext(row).getObjectId()); + record.setLabel(data.label(row)); + record.setPosition(data.position(row)); + record.setLimit(data.limit(row)); + record.setCapacity(data.capacity(row)); + return record; + })); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DominatorTreeRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DominatorTreeRoute.java new file mode 100644 index 0000000..e5e04ef --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DominatorTreeRoute.java
@@ -0,0 +1,147 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.dominatortree.BaseRecord; +import org.eclipse.jifa.worker.vo.heapdump.dominatortree.ClassRecord; +import org.eclipse.jifa.worker.vo.heapdump.dominatortree.DefaultRecord; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.internal.snapshot.inspections.DominatorQuery; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import java.lang.reflect.Constructor; +import java.util.List; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class DominatorTreeRoute extends HeapBaseRoute { + + private static Constructor<?> DEFAULT_NODE; + + static { + try { + Class<?> clazz = Class.forName("org.eclipse.mat.internal.snapshot.inspections.DominatorQuery$Node"); + DEFAULT_NODE = clazz.getConstructor(int.class); + DEFAULT_NODE.setAccessible(true); + ASSERT.notNull(DEFAULT_NODE); + + } catch (Exception e) { + throw new JifaException(e); + } + } + + @RouteMeta(path = "/dominatorTree/roots") + void roots(Future<PageView<BaseRecord>> future, @ParamKey("file") String file, + @ParamKey("grouping") Grouping grouping, PagingRequest pagingRequest) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + DominatorQuery query = new DominatorQuery(); + query.snapshot = snapshot; + query.groupBy = grouping.internalGroping; + DominatorQuery.Tree tree = query.execute(HeapDumpSupport.VOID_LISTENER); + + if (grouping == Grouping.NONE) { + future.complete(buildDefaultRecord(snapshot, tree, tree.getElements(), pagingRequest)); + } else if (grouping == Grouping.BY_CLASS) { + future.complete(buildClassRecord(tree, tree.getElements(), pagingRequest)); + } + } + + @RouteMeta(path = "/dominatorTree/children") + void children(Future<PageView<BaseRecord>> future, @ParamKey("file") String file, + @ParamKey("grouping") Grouping grouping, PagingRequest pagingRequest, + @ParamKey("parentObjectId") int parentObjectId) throws Exception { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + DominatorQuery query = new DominatorQuery(); + query.snapshot = snapshot; + query.groupBy = grouping.internalGroping; + DominatorQuery.Tree tree = query.execute(HeapDumpSupport.VOID_LISTENER); + + if (grouping == Grouping.NONE) { + Object parentNode = DEFAULT_NODE.newInstance(parentObjectId); + future.complete(buildDefaultRecord(snapshot, tree, tree.getChildren(parentNode), pagingRequest)); + } else if (grouping == Grouping.BY_CLASS) { + + } + } + + private PageView<BaseRecord> buildDefaultRecord(ISnapshot snapshot, DominatorQuery.Tree tree, List<?> elements, + PagingRequest pagingRequest) { + + return PageViewBuilder.build(elements, pagingRequest, e -> { + try { + DefaultRecord record = new DefaultRecord(); + int objectId = tree.getContext(e).getObjectId(); + IObject object = snapshot.getObject(objectId); + record.setObjectId(objectId); + record.setSuffix(HeapDumpSupport.suffix(object.getGCRootInfo())); + record.setObjectType(HeapObject.Type.typeOf(object)); + record.setGCRoot(snapshot.isGCRoot(objectId)); + record.setLabel((String) tree.getColumnValue(e, 0)); + record.setShallowSize(((Bytes) tree.getColumnValue(e, 1)).getValue()); + record.setRetainedSize(((Bytes) tree.getColumnValue(e, 2)).getValue()); + record.setPercent((Double) tree.getColumnValue(e, 3)); + return record; + } catch (SnapshotException ex) { + throw new JifaException(ex); + } + }); + } + + private PageView<BaseRecord> buildClassRecord(DominatorQuery.Tree tree, List<?> elements, + PagingRequest pagingRequest) { + + elements.sort((e1, e2) -> ((Bytes) tree.getColumnValue(e2, 3)).compareTo(tree.getColumnValue(e1, 3))); + + return PageViewBuilder.build(elements, pagingRequest, e -> { + ClassRecord record = new ClassRecord(); + int objectId = tree.getContext(e).getObjectId(); + record.setObjectId(objectId); + record.setLabel((String) tree.getColumnValue(e, 0)); + record.setObjects((Integer) tree.getColumnValue(e, 1)); + record.setShallowSize(((Bytes) tree.getColumnValue(e, 2)).getValue()); + record.setRetainedSize(((Bytes) tree.getColumnValue(e, 3)).getValue()); + record.setPercent((Double) tree.getColumnValue(e, 4)); + return record; + }); + } + + public enum Grouping { + + NONE(DominatorQuery.Grouping.NONE), + + BY_CLASS(DominatorQuery.Grouping.BY_CLASS), + + BY_CLASSLOADER(DominatorQuery.Grouping.BY_CLASSLOADER), + + BY_PACKAGE(DominatorQuery.Grouping.BY_PACKAGE); + + DominatorQuery.Grouping internalGroping; + + Grouping(DominatorQuery.Grouping internalGroping) { + this.internalGroping = internalGroping; + } + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DuplicatedClassesRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DuplicatedClassesRoute.java new file mode 100644 index 0000000..587b647 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/DuplicatedClassesRoute.java
@@ -0,0 +1,84 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.vo.heapdump.duplicatedclass.ClassLoaderRecord; +import org.eclipse.jifa.worker.vo.heapdump.duplicatedclass.ClassRecord; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.inspections.DuplicatedClassesQuery; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.GCRootInfo; +import org.eclipse.mat.snapshot.model.IClass; + +import java.util.List; + +class DuplicatedClassesRoute extends HeapBaseRoute { + + @RouteMeta(path = "/duplicatedClasses/classes") + void classRecords(Future<PageView<ClassRecord>> future, @ParamKey("file") String file, + PagingRequest pagingRequest) throws Exception { + + DuplicatedClassesQuery query = new DuplicatedClassesQuery(); + query.snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + + List<?> classes = result.getElements(); + classes.sort((o1, o2) -> ((List) o2).size() - ((List) o1).size()); + future.complete(PageViewBuilder.build(classes, pagingRequest, r -> { + ClassRecord record = new ClassRecord(); + record.setLabel((String) result.getColumnValue(r, 0)); + record.setCount((Integer) result.getColumnValue(r, 1)); + return record; + })); + } + + @RouteMeta(path = "/duplicatedClasses/classLoaders") + void classLoaderRecords(Future<PageView<ClassLoaderRecord>> future, @ParamKey("file") String file, + @ParamKey("index") int index, PagingRequest pagingRequest) throws Exception { + DuplicatedClassesQuery query = new DuplicatedClassesQuery(); + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + query.snapshot = snapshot; + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + + List<?> classes = result.getElements(); + classes.sort((o1, o2) -> ((List) o2).size() - ((List) o1).size()); + List<?> classLoaders = (List<?>) classes.get(index); + future.complete(PageViewBuilder.build(classLoaders, pagingRequest, r -> { + ClassLoaderRecord record = new ClassLoaderRecord(); + record.setLabel((String) result.getColumnValue(r, 0)); + record.setDefinedClassesCount((Integer) result.getColumnValue(r, 2)); + record.setInstantiatedObjectsCount((Integer) result.getColumnValue(r, 3)); + GCRootInfo[] roots; + try { + roots = ((IClass) r).getGCRootInfo(); + } catch (SnapshotException e) { + throw new JifaException(e); + } + int id = ((IClass) r).getClassLoaderId(); + record.setObjectId(id); + record.setGCRoot(snapshot.isGCRoot(id)); + record.setSuffix(roots != null ? GCRootInfo.getTypeSetAsString(roots) : null); + return record; + })); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/GCRootRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/GCRootRoute.java new file mode 100644 index 0000000..08e49f8 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/GCRootRoute.java
@@ -0,0 +1,106 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.gcroot.Result; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.inspections.GCRootsQuery; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import java.util.List; +import java.util.stream.Collectors; + +class GCRootRoute extends HeapBaseRoute { + + @RouteMeta(path = "/GCRoots") + void roots(Future<List<Result>> future, @ParamKey("file") String file) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + GCRootsQuery query = new GCRootsQuery(); + query.snapshot = snapshot; + + IResultTree tree = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + future.complete(tree.getElements().stream().map(e -> { + Result r = new Result(); + r.setClassName((String) tree.getColumnValue(e, 0)); + r.setObjects((Integer) tree.getColumnValue(e, 1)); + return r; + }).collect(Collectors.toList())); + } + + @RouteMeta(path = "/GCRoots/classes") + void classes(Future<PageView<Result>> future, @ParamKey("file") String file, + @ParamKey("rootTypeIndex") int rootTypeIndex, PagingRequest pagingRequest) throws Exception { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + GCRootsQuery query = new GCRootsQuery(); + query.snapshot = snapshot; + + IResultTree tree = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + Object root = tree.getElements().get(rootTypeIndex); + List<?> classes = tree.getChildren(root); + future.complete(PageViewBuilder.build(classes, pagingRequest, clazz -> { + Result r = new Result(); + r.setClassName((String) tree.getColumnValue(clazz, 0)); + r.setObjects((Integer) tree.getColumnValue(clazz, 1)); + r.setObjectId(tree.getContext(clazz).getObjectId()); + return r; + })); + } + + @RouteMeta(path = "/GCRoots/class/objects") + void objects(Future<PageView<HeapObject>> future, @ParamKey("file") String file, + @ParamKey("rootTypeIndex") int rootTypeIndex, @ParamKey("classIndex") int classIndex, + PagingRequest pagingRequest) throws Exception { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + GCRootsQuery query = new GCRootsQuery(); + query.snapshot = snapshot; + + IResultTree tree = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + Object root = tree.getElements().get(rootTypeIndex); + List<?> classes = tree.getChildren(root); + Object clazz = classes.get(classIndex); + List<?> objects = tree.getChildren(clazz); + future.complete(PageViewBuilder.build(objects, pagingRequest, o -> { + try { + HeapObject ho = new HeapObject(); + int objectId = tree.getContext(o).getObjectId(); + IObject object = snapshot.getObject(objectId); + ho.setLabel(object.getDisplayName()); + ho.setObjectId(objectId); + ho.setShallowSize(object.getUsedHeapSize()); + ho.setRetainedSize(object.getRetainedHeapSize()); + ho.setObjectType(HeapObject.Type.typeOf(object)); + ho.setGCRoot(snapshot.isGCRoot(objectId)); + ho.setSuffix(HeapDumpSupport.suffix(object.getGCRootInfo())); + ho.setHasOutbound(true); + ho.setHasInbound(true); + return ho; + } catch (SnapshotException e) { + throw new JifaException(e); + } + })); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HeapBaseRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HeapBaseRoute.java new file mode 100644 index 0000000..d8690c6 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HeapBaseRoute.java
@@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.worker.route.BaseRoute; +import org.eclipse.jifa.worker.route.MappingPrefix; + +import java.util.ArrayList; +import java.util.List; + +@MappingPrefix("/heap-dump/:file") +public class HeapBaseRoute extends BaseRoute { + + private static List<Class<? extends HeapBaseRoute>> ROUTES = new ArrayList<>(); + + static { + ROUTES.add(OverviewRoute.class); + ROUTES.add(ObjectRoute.class); + ROUTES.add(InspectorRoute.class); + ROUTES.add(DominatorTreeRoute.class); + ROUTES.add(HistogramRoute.class); + ROUTES.add(UnreachableObjectsRoute.class); + ROUTES.add(ClassLoaderRoute.class); + ROUTES.add(DuplicatedClassesRoute.class); + ROUTES.add(SystemPropertyRoute.class); + ROUTES.add(ThreadRoute.class); + ROUTES.add(ObjectListRoute.class); + ROUTES.add(ClassReferenceRoute.class); + ROUTES.add(OQLRoute.class); + ROUTES.add(DirectByteBufferRoute.class); + ROUTES.add(GCRootRoute.class); + ROUTES.add(PathToGCRootsRoute.class); + ROUTES.add(CompareRoute.class); + ROUTES.add(LeakRoute.class); + } + + public static List<Class<? extends HeapBaseRoute>> routes() { + return ROUTES; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HistogramRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HistogramRoute.java new file mode 100644 index 0000000..58e2e50 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/HistogramRoute.java
@@ -0,0 +1,101 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.vo.heapdump.histogram.Record; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.inspections.HistogramQuery; +import org.eclipse.mat.query.IResult; +import org.eclipse.mat.snapshot.ClassHistogramRecord; +import org.eclipse.mat.snapshot.Histogram; +import org.eclipse.mat.snapshot.ISnapshot; + +import java.util.List; + +class HistogramRoute extends HeapBaseRoute { + + @RouteMeta(path = "/histogram") + void histogram(Future<PageView<Record>> future, @ParamKey("file") String file, + @ParamKey("groupingBy") Grouping groupingBy, @ParamKey(value = "ids", mandatory = false) int[] ids, + PagingRequest pagingRequest) throws Exception { + try { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + HistogramQuery query = new HistogramQuery(); + query.snapshot = snapshot; + if (ids != null) { + query.objects = HeapDumpSupport.buildHeapObjectArgument(ids); + } + + query.groupBy = groupingBy.gb; + + IResult result; + result = query.execute(HeapDumpSupport.VOID_LISTENER); + + if (groupingBy.gb == HistogramQuery.Grouping.BY_CLASS) { + + Histogram histogram = (Histogram) result; + List<ClassHistogramRecord> records = (List) histogram.getClassHistogramRecords(); + records.forEach(record -> { + try { + record.calculateRetainedSize(snapshot, true, true, HeapDumpSupport.VOID_LISTENER); + } catch (SnapshotException e) { + throw new JifaException(e); + } + }); + records.sort((o1, o2) -> (int) (o2.getUsedHeapSize() - o1.getUsedHeapSize())); + future.complete(PageViewBuilder.build(records, pagingRequest, + record -> new Record(record.getClassId(), record.getLabel(), + Record.Type.CLASS, + record.getNumberOfObjects(), + record.getUsedHeapSize(), + record.getRetainedHeapSize(), + record.getNumberOfYoungObjects(), + record.getUsedHeapSizeOfYoung(), + record.getNumberOfOldObjects(), + record.getUsedHeapSizeOfOld()))); + } else { + // unsupported now. + throw new IllegalArgumentException(); + } + } catch (Exception e) { + throw new JifaException(e); + } + } + + public enum Grouping { + + BY_CLASS(HistogramQuery.Grouping.BY_CLASS), + + BY_SUPERCLASS(HistogramQuery.Grouping.BY_SUPERCLASS), + + BY_CLASSLOADER(HistogramQuery.Grouping.BY_CLASSLOADER), + + BY_PACKAGE(HistogramQuery.Grouping.BY_PACKAGE); + + HistogramQuery.Grouping gb; + + Grouping(HistogramQuery.Grouping groupingBy) { + this.gb = groupingBy; + } + } + +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/InspectorRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/InspectorRoute.java new file mode 100644 index 0000000..6381d7a --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/InspectorRoute.java
@@ -0,0 +1,206 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.worker.route.MappingPrefix; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.inspector.FieldView; +import org.eclipse.jifa.worker.vo.heapdump.inspector.ObjectView; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.*; + +import java.util.ArrayList; +import java.util.List; + +import static org.eclipse.jifa.common.Constant.EMPTY_STRING; + +@MappingPrefix("/inspector") +class InspectorRoute extends HeapBaseRoute { + + @RouteMeta(path = "/addressToId") + void addressToId(Future<Integer> future, @ParamKey("file") String file, + @ParamKey("objectAddress") long address) throws SnapshotException { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + future.complete(snapshot.mapAddressToId(address)); + } + + @RouteMeta(path = "/value") + void value(Future<String> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws SnapshotException { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IObject object = snapshot.getObject(objectId); + + String txt = object.getClassSpecificName(); + + future.complete(txt != null ? txt : EMPTY_STRING); + } + + @RouteMeta(path = "/objectView") + void objectView(Future<ObjectView> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws SnapshotException { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IObject object = snapshot.getObject(objectId); + ObjectView view = new ObjectView(); + + // object address and name + // for non-class object, name = the name of object's class + // for class object, name = class name + view.setObjectAddress(object.getObjectAddress()); + IClass iClass = object instanceof IClass ? (IClass) object : object.getClazz(); + view.setName(iClass.getName()); + view.setObjectType(HeapObject.Type.typeOf(object)); + view.setGCRoot(snapshot.isGCRoot(objectId)); + + // class name and address of the object + IClass clazz = object.getClazz(); + view.setClassLabel(clazz.getTechnicalName()); + view.setClassGCRoot(clazz.getGCRootInfo() != null); + + // super class name + if (iClass.getSuperClass() != null) { + view.setSuperClassName(iClass.getSuperClass().getName()); + } + + // class loader name and address + IObject classLoader = snapshot.getObject(iClass.getClassLoaderId()); + view.setClassLoaderLabel(classLoader.getTechnicalName()); + view.setClassLoaderGCRoot(classLoader.getGCRootInfo() != null); + + view.setShallowSize(object.getUsedHeapSize()); + view.setRetainedSize(object.getRetainedHeapSize()); + // gc root + GCRootInfo[] gcRootInfo = object.getGCRootInfo(); + view.setGcRootInfo( + gcRootInfo != null ? "GC root: " + GCRootInfo.getTypeSetAsString(object.getGCRootInfo()) : "no GC root"); + + HeapLayout heapLayout = snapshot.getSnapshotInfo().getHeapLayout(); + view.setLocationType(ObjectView.locationTypeOf(heapLayout.genOf(view.getObjectAddress()))); + future.complete(view); + } + + @RouteMeta(path = "/staticFields") + void staticFields(Future<PageView<FieldView>> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId, PagingRequest pagingRequest) throws SnapshotException { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IObject object = snapshot.getObject(objectId); + boolean isClass = object instanceof IClass; + IClass clazz = isClass ? (IClass) object : object.getClazz(); + + List<Field> fields = new ArrayList<>(); + + do { + List<Field> staticFields = clazz.getStaticFields(); + for (Field staticField : staticFields) { + if (!staticField.getName().startsWith("<")) { + fields.add(staticField); + } + } + } while (!isClass && (clazz = clazz.getSuperClass()) != null); + + complete(future, pagingRequest, fields); + } + + @RouteMeta(path = "/fields") + void fields(Future<PageView<FieldView>> future, @ParamKey("file") String file, @ParamKey("objectId") int objectId, + PagingRequest pagingRequest) throws SnapshotException { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IObject object = snapshot.getObject(objectId); + + if (object instanceof IPrimitiveArray) { + List<FieldView> fvs = new ArrayList<>(); + IPrimitiveArray pa = (IPrimitiveArray) object; + int firstIndex = (pagingRequest.getPage() - 1) * pagingRequest.getPageSize(); + int lastIndex = Math.min(firstIndex + pagingRequest.getPageSize(), pa.getLength()); + for (int i = firstIndex; i < lastIndex; i++) { + fvs.add(new FieldView(pa.getType(), "[" + i + "]", pa.getValueAt(i).toString())); + } + future.complete(new PageView<>(pagingRequest, pa.getLength(), fvs)); + return; + } else if (object instanceof IObjectArray) { + List<FieldView> fvs = new ArrayList<>(); + IObjectArray oa = (IObjectArray) object; + int firstIndex = (pagingRequest.getPage() - 1) * pagingRequest.getPageSize(); + int lastIndex = Math.min(firstIndex + pagingRequest.getPageSize(), oa.getLength()); + for (int i = firstIndex; i < lastIndex; i++) { + long refs[] = oa.getReferenceArray(i, 1); + int refObjectId = 0; + if (refs[0] != 0) { + refObjectId = snapshot.mapAddressToId(refs[0]); + } + String value = null; + if (refObjectId != 0) { + value = getObjectValue(snapshot.getObject(refObjectId)); + } + fvs.add(new FieldView(IObject.Type.OBJECT, "[" + i + "]", value, refObjectId)); + } + future.complete(new PageView<>(pagingRequest, oa.getLength(), fvs)); + return; + } + + List<Field> fields = new ArrayList<>(); + boolean isClass = object instanceof IClass; + IClass clazz = isClass ? (IClass) object : object.getClazz(); + + if (object instanceof IInstance) { + fields.addAll(((IInstance) object).getFields()); + } else if (object instanceof IClass) { + do { + List<Field> staticFields = clazz.getStaticFields(); + for (Field staticField : staticFields) { + if (staticField.getName().startsWith("<")) { + fields.add(staticField); + } + } + } while ((clazz = clazz.getSuperClass()) != null); + + } + complete(future, pagingRequest, fields); + } + + private void complete(Future<PageView<FieldView>> future, PagingRequest pagingRequest, List<Field> totalFields) { + future.complete(PageViewBuilder.build(totalFields, pagingRequest, field -> { + FieldView fv = new FieldView(); + fv.setFieldType(field.getType()); + fv.setName(field.getName()); + Object value = field.getValue(); + if (value instanceof ObjectReference) { + try { + fv.setObjectId(((ObjectReference) value).getObjectId()); + fv.setValue(getObjectValue(((ObjectReference) value).getObject())); + } catch (SnapshotException e) { + throw new JifaException(e); + } + } else if (value != null) { + fv.setValue(value.toString()); + } + return fv; + })); + } + + private String getObjectValue(IObject o) { + String text = o.getClassSpecificName(); + return text != null ? text : o.getTechnicalName(); + } + +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/LeakRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/LeakRoute.java new file mode 100644 index 0000000..e922bc2 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/LeakRoute.java
@@ -0,0 +1,145 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import com.google.common.base.Strings; +import io.vertx.core.Future; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.support.heapdump.SnapshotContext; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.leak.Report; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.internal.Messages; +import org.eclipse.mat.internal.snapshot.SnapshotQueryContext; +import org.eclipse.mat.internal.snapshot.inspections.Path2GCRootsQuery; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.query.IResult; +import org.eclipse.mat.query.IResultPie; +import org.eclipse.mat.query.refined.RefinedResultBuilder; +import org.eclipse.mat.query.refined.RefinedTree; +import org.eclipse.mat.query.results.CompositeResult; +import org.eclipse.mat.query.results.TextResult; +import org.eclipse.mat.report.QuerySpec; +import org.eclipse.mat.report.SectionSpec; +import org.eclipse.mat.report.Spec; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import java.util.ArrayList; +import java.util.List; + +class LeakRoute extends HeapBaseRoute { + + private static final String OVERVIEW_PATTERN = Messages.LeakHunterQuery_Overview; + + private static final String PROBLEM_SUSPECT_PATTERN = + Messages.LeakHunterQuery_ProblemSuspect.substring(0, Messages.LeakHunterQuery_ProblemSuspect.indexOf("{0}")); + + private static final String HIND_PATTERN = + Messages.LeakHunterQuery_Hint.substring(0, Messages.LeakHunterQuery_Hint.indexOf("{0}")); + + private static final String DESC_PATTERN = Messages.LeakHunterQuery_Description; + + private static final String SHORTEST_PATHS_PATTERN = Messages.LeakHunterQuery_ShortestPaths; + + @RouteMeta(path = "/leak/report") + void report(Future<Report> future, @ParamKey("file") String file) throws Exception { + SnapshotContext context = Analyzer.getOrOpenSnapshotContext(file); + IResult result = context.leakReport().getResult(); + Report report = new Report(); + if (result instanceof TextResult) { + report.setInfo(((TextResult) result).getText()); + } else if (result instanceof SectionSpec) { + report.setUseful(true); + SectionSpec sectionSpec = (SectionSpec) result; + report.setName(sectionSpec.getName()); + List<Spec> specs = sectionSpec.getChildren(); + for (int i = 0; i < specs.size(); i++) { + QuerySpec spec = (QuerySpec) specs.get(i); + String name = spec.getName(); + if (Strings.isNullOrEmpty(name)) { + continue; + } + if (name.startsWith(OVERVIEW_PATTERN)) { + IResultPie irtPie = (IResultPie) spec.getResult(); + List<? extends IResultPie.Slice> pieSlices = irtPie.getSlices(); + + List<Report.Slice> slices = new ArrayList<>(); + for (IResultPie.Slice slice : pieSlices) { + slices.add(new Report.Slice(slice.getLabel(), HeapDumpSupport.fetchObjectId(slice.getContext()), + slice.getValue(), slice.getDescription())); + } + report.setSlices(slices); + + } else if (name.startsWith(PROBLEM_SUSPECT_PATTERN) || name.startsWith(HIND_PATTERN)) { + Report.Record suspect = new Report.Record(); + suspect.setIndex(i); + suspect.setName(name); + CompositeResult cr = (CompositeResult) spec.getResult(); + List<CompositeResult.Entry> entries = cr.getResultEntries(); + for (CompositeResult.Entry entry : entries) { + String entryName = entry.getName(); + if (Strings.isNullOrEmpty(entryName)) { + IResult r = entry.getResult(); + if (r instanceof QuerySpec && ((QuerySpec) r).getName().equals(SHORTEST_PATHS_PATTERN)) { + Path2GCRootsQuery.Tree tree = (Path2GCRootsQuery.Tree) ((QuerySpec) r).getResult(); + RefinedResultBuilder builder = new RefinedResultBuilder( + new SnapshotQueryContext(context.getSnapshot()), tree); + RefinedTree rst = (RefinedTree) builder.build(); + List<?> elements = rst.getElements(); + List<Report.ShortestPath> paths = new ArrayList<>(); + suspect.setPaths(paths); + for (Object row : elements) { + paths.add(buildPath(context.getSnapshot(), rst, row)); + } + } + } else if ((entryName.startsWith(DESC_PATTERN) || entryName.startsWith(OVERVIEW_PATTERN))) { + TextResult desText = (TextResult) entry.getResult(); + suspect.setDesc(desText.getText()); + } + } + List<Report.Record> records = report.getRecords(); + if (records == null) { + report.setRecords(records = new ArrayList<>()); + } + records.add(suspect); + } + } + } + future.complete(report); + } + + private Report.ShortestPath buildPath(ISnapshot snapshot, RefinedTree rst, Object row) throws SnapshotException { + Report.ShortestPath shortestPath = new Report.ShortestPath(); + shortestPath.setLabel((String) rst.getColumnValue(row, 0)); + shortestPath.setShallowSize(((Bytes) rst.getColumnValue(row, 1)).getValue()); + shortestPath.setRetainedSize(((Bytes) rst.getColumnValue(row, 2)).getValue()); + int objectId = rst.getContext(row).getObjectId(); + shortestPath.setObjectId(objectId); + IObject object = snapshot.getObject(objectId); + shortestPath.setGCRoot(snapshot.isGCRoot(objectId)); + shortestPath.setObjectType(HeapObject.Type.typeOf(object)); + + if (rst.hasChildren(row)) { + List<Report.ShortestPath> children = new ArrayList<>(); + shortestPath.setChildren(children); + for (Object c : rst.getChildren(row)) { + children.add(buildPath(snapshot, rst, c)); + } + } + return shortestPath; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OQLRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OQLRoute.java new file mode 100644 index 0000000..35f6ef3 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OQLRoute.java
@@ -0,0 +1,104 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import io.vertx.core.Future; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.oql.TableResult; +import org.eclipse.jifa.worker.vo.heapdump.oql.TextResult; +import org.eclipse.jifa.worker.vo.heapdump.oql.TreeResult; +import org.eclipse.mat.inspections.OQLQuery; +import org.eclipse.mat.query.Column; +import org.eclipse.mat.query.IContextObject; +import org.eclipse.mat.query.IResultTable; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.snapshot.IOQLQuery; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +class OQLRoute extends HeapBaseRoute { + + @RouteMeta(path = "/oql") + void oql(Future<Object> future, @ParamKey("file") String file, @ParamKey("oql") String oql, + PagingRequest pagingRequest) throws Exception { + OQLQuery query = new OQLQuery(); + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + query.snapshot = snapshot; + query.queryString = oql; + IOQLQuery.Result qr = query.execute(HeapDumpSupport.VOID_LISTENER); + + if (qr instanceof IResultTree) { + future.complete(new TreeResult(PageViewBuilder.build(((IResultTree) qr).getElements(), pagingRequest, e -> { + try { + int objectId = ((IResultTree) qr).getContext(e).getObjectId(); + IObject o = snapshot.getObject(objectId); + HeapObject ho = new HeapObject(); + ho.setObjectId(objectId); + ho.setLabel(o.getDisplayName()); + ho.setSuffix(HeapDumpSupport.suffix(o.getGCRootInfo())); + ho.setShallowSize(o.getUsedHeapSize()); + ho.setRetainedSize(o.getRetainedHeapSize()); + ho.setGCRoot(snapshot.isGCRoot(objectId)); + ho.setObjectType(HeapObject.Type.typeOf(o)); + ho.setHasOutbound(true); + return ho; + } catch (Exception ex) { + throw new JifaException(ex); + } + }))); + } else if (qr instanceof IResultTable) { + IResultTable table = (IResultTable) qr; + Column[] columns = table.getColumns(); + List<String> cs = Arrays.stream(columns).map(Column::getLabel).collect(Collectors.toList()); + PageView<TableResult.Entry> pv = PageViewBuilder.build(new PageViewBuilder.Callback<Object>() { + @Override + public int totalSize() { + return table.getRowCount(); + } + + @Override + public Object get(int index) { + return table.getRow(index); + } + }, pagingRequest, o -> { + List<Object> l = new ArrayList<>(); + for (int i = 0; i < columns.length; i++) { + Object columnValue = table.getColumnValue(o, i); + + l.add(columnValue != null ? columnValue.toString() : null); + } + IContextObject context = table.getContext(o); + return new TableResult.Entry( + context != null ? context.getObjectId() : HeapDumpSupport.ILLEGAL_OBJECT_ID, l); + }); + future.complete(new TableResult(cs, pv)); + } else if (qr instanceof org.eclipse.mat.query.results.TextResult) { + future.complete(new TextResult(((org.eclipse.mat.query.results.TextResult) qr).getText())); + } else { + throw new UnsupportedOperationException(); + } + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectListRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectListRoute.java new file mode 100644 index 0000000..62c24d1 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectListRoute.java
@@ -0,0 +1,75 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import io.vertx.core.Future; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class ObjectListRoute extends HeapBaseRoute { + + private static void fill(Future<PageView<HeapObject>> future, ISnapshot snapshot, int src, int[] objId, + PagingRequest pagingRequest, boolean outbound) { + future.complete(PageViewBuilder.build(objId, pagingRequest, id -> { + try { + HeapObject o = new HeapObject(); + IObject object = snapshot.getObject(id); + o.setObjectId(id); + o.setLabel(object.getDisplayName()); + o.setShallowSize(object.getUsedHeapSize()); + o.setRetainedSize(object.getRetainedHeapSize()); + o.setObjectType(HeapObject.Type.typeOf(object)); + o.setGCRoot(snapshot.isGCRoot(id)); + o.setHasOutbound(true); + o.setHasInbound(true); + o.setPrefix(HeapDumpSupport.prefix(snapshot, outbound ? src : id, outbound ? id : src)); + o.setSuffix(HeapDumpSupport.suffix(snapshot, id)); + return o; + } catch (Exception e) { + throw new RuntimeException(e); + } + })); + } + + @RouteMeta(path = "/outbounds") + void outbounds(Future<PageView<HeapObject>> future, @ParamKey("file") String file, PagingRequest pagingRequest, + @ParamKey("objectId") int objectId) throws Exception { + + ASSERT.isTrue(objectId >= 0, "Object id must be greater than or equal to 0"); + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + int[] objId = snapshot.getOutboundReferentIds(objectId); + fill(future, snapshot, objectId, objId, pagingRequest, true); + } + + @RouteMeta(path = "/inbounds") + void inbounds(Future<PageView<HeapObject>> future, @ParamKey("file") String file, PagingRequest pagingRequest, + @ParamKey("objectId") int objectId) throws Exception { + + ASSERT.isTrue(objectId >= 0, "Object id must be greater than or equal to 0"); + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + int[] objId = snapshot.getInboundRefererIds(objectId); + fill(future, snapshot, objectId, objId, pagingRequest, false); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectRoute.java new file mode 100644 index 0000000..321d54d --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ObjectRoute.java
@@ -0,0 +1,47 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import io.vertx.core.Future; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IObject; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class ObjectRoute extends HeapBaseRoute { + + @RouteMeta(path = "/object") + void info(Future<HeapObject> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws Exception { + + ASSERT.isTrue(objectId >= 0, "Object id must be greater than or equal to 0"); + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + + HeapObject o = new HeapObject(); + IObject object = snapshot.getObject(objectId); + o.setObjectId(objectId); + o.setLabel(object.getDisplayName()); + o.setShallowSize(object.getUsedHeapSize()); + o.setRetainedSize(object.getRetainedHeapSize()); + o.setObjectType(HeapObject.Type.typeOf(object)); + o.setGCRoot(snapshot.isGCRoot(objectId)); + o.setHasOutbound(true); + o.setSuffix(HeapDumpSupport.suffix(snapshot, objectId)); + future.complete(o); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OverviewRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OverviewRoute.java new file mode 100644 index 0000000..11a9455 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/OverviewRoute.java
@@ -0,0 +1,56 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import io.vertx.core.Future; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.overview.BigObject; +import org.eclipse.jifa.worker.vo.heapdump.overview.Details; +import org.eclipse.mat.inspections.BiggestObjectsPieQuery; +import org.eclipse.mat.query.IResultPie; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.SnapshotInfo; + +import java.util.List; +import java.util.stream.Collectors; + +class OverviewRoute extends HeapBaseRoute { + + @RouteMeta(path = "/details") + void details(Future<Details> future, @ParamKey("file") String file) { + SnapshotInfo snapshotInfo = Analyzer.getOrOpenSnapshotContext(file).getSnapshot().getSnapshotInfo(); + Details details = new Details(snapshotInfo.getJvmInfo(), snapshotInfo.getIdentifierSize(), + snapshotInfo.getCreationDate().getTime(), snapshotInfo.getNumberOfObjects(), + snapshotInfo.getNumberOfGCRoots(), snapshotInfo.getNumberOfClasses(), + snapshotInfo.getNumberOfClassLoaders(), snapshotInfo.getUsedHeapSize(), + snapshotInfo.layoutAvailable()); + future.complete(details); + } + + @RouteMeta(path = "/biggestObjects") + void biggestObjects(Future<List<BigObject>> future, @ParamKey("file") String file) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + BiggestObjectsPieQuery query = new BiggestObjectsPieQuery(); + query.snapshot = snapshot; + List<? extends IResultPie.Slice> slices = query.execute(HeapDumpSupport.VOID_LISTENER).getSlices(); + future.complete(slices.stream() + .map(slice -> new BigObject(slice.getLabel(), + slice.getContext() != null ? slice.getContext().getObjectId() + : HeapDumpSupport.ILLEGAL_OBJECT_ID, + slice.getValue(), slice.getDescription())) + .collect(Collectors.toList())); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/PathToGCRootsRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/PathToGCRootsRoute.java new file mode 100644 index 0000000..0ff35ea --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/PathToGCRootsRoute.java
@@ -0,0 +1,136 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.gcrootpath.Result; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.snapshot.IPathsFromGCRootsComputer; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.IClass; +import org.eclipse.mat.snapshot.model.IObject; + +import java.util.*; +import java.util.regex.Pattern; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class PathToGCRootsRoute extends HeapBaseRoute { + private List<String> excludes = + Arrays.asList("java.lang.ref.WeakReference:referent", "java.lang.ref.SoftReference:referent"); + + private static Map<IClass, Set<String>> convert(ISnapshot snapshot, + List<String> excludes) throws SnapshotException { + Map<IClass, Set<String>> excludeMap = null; + + if (excludes != null && !excludes.isEmpty()) { + excludeMap = new HashMap<IClass, Set<String>>(); + + for (String entry : excludes) { + String pattern = entry; + Set<String> fields = null; + int colon = entry.indexOf(':'); + + if (colon >= 0) { + fields = new HashSet<String>(); + + StringTokenizer tokens = new StringTokenizer(entry.substring(colon + 1), ","); //$NON-NLS-1$ + while (tokens.hasMoreTokens()) + fields.add(tokens.nextToken()); + + pattern = pattern.substring(0, colon); + } + + for (IClass clazz : snapshot.getClassesByName(Pattern.compile(pattern), true)) + excludeMap.put(clazz, fields); + } + } + + return excludeMap; + } + + @RouteMeta(path = "/pathToGCRoots") + void path(Future<Result> future, @ParamKey("file") String file, @ParamKey("origin") int origin, + @ParamKey("skip") int skip, @ParamKey("count") int count) throws Exception { + + ASSERT.isTrue(origin >= 0).isTrue(skip >= 0).isTrue(count > 0); + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + Map<IClass, Set<String>> excludeMap = convert(snapshot, excludes); + + IPathsFromGCRootsComputer computer = snapshot.getPathsFromGCRoots(origin, excludeMap); + + List<int[]> paths = new ArrayList<>(); + int index = 0; + int[] current; + int get = 0; + while (get < count && (current = computer.getNextShortestPath()) != null) { + if (index < skip) { + index++; + continue; + } + paths.add(current); + get++; + } + future.complete(build(snapshot, origin, paths, computer.getNextShortestPath() != null)); + } + + private Result build(ISnapshot snapshot, int originId, List<int[]> paths, boolean hasMore) throws Exception { + + Result result = new Result(); + result.setCount(paths.size()); + result.setHasMore(hasMore); + Result.Node origin = new Result.Node(); + IObject object = snapshot.getObject(originId); + origin.setOrigin(true); + origin.setObjectId(originId); + origin.setLabel(object.getDisplayName()); + origin.setSuffix(HeapDumpSupport.suffix(snapshot, originId)); + origin.setGCRoot(snapshot.isGCRoot(originId)); + origin.setObjectType(HeapObject.Type.typeOf(object)); + origin.setShallowSize(object.getUsedHeapSize()); + origin.setRetainedSize(object.getRetainedHeapSize()); + result.setTree(origin); + + if (paths.size() == 0) { + return result; + } + + for (int[] path : paths) { + Result.Node parentNode = origin; + for (int index = 1; index < path.length; index++) { + int childId = path[index]; + Result.Node childNode = parentNode.getChild(childId); + if (childNode == null) { + IObject childObj = snapshot.getObject(childId); + childNode = new Result.Node(); + childNode.setObjectId(childId); + childNode.setPrefix(HeapDumpSupport.prefix(snapshot, childId, parentNode.getObjectId())); + childNode.setLabel(childObj.getDisplayName()); + childNode.setSuffix(HeapDumpSupport.suffix(snapshot, childId)); + childNode.setGCRoot(snapshot.isGCRoot(childId)); + childNode.setObjectType(HeapObject.Type.typeOf(childObj)); + childNode.setShallowSize(childObj.getUsedHeapSize()); + childNode.setRetainedSize(childObj.getRetainedHeapSize()); + parentNode.addChild(childNode); + } + parentNode = childNode; + } + } + return result; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/SystemPropertyRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/SystemPropertyRoute.java new file mode 100644 index 0000000..2be3a2f --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/SystemPropertyRoute.java
@@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import io.vertx.core.Future; +import org.eclipse.mat.inspections.SystemPropertiesQuery; +import org.eclipse.mat.query.IResultTable; + +import java.util.HashMap; +import java.util.Map; + +class SystemPropertyRoute extends HeapBaseRoute { + + @RouteMeta(path = "/systemProperties") + void systemProperty(Future<Map<String, String>> future, @ParamKey("file") String file) throws Exception { + SystemPropertiesQuery query = new SystemPropertiesQuery(); + query.snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IResultTable result = query.execute(HeapDumpSupport.VOID_LISTENER); + Map<String, String> sp = new HashMap<>(); + int count = result.getRowCount(); + for (int i = 0; i < count; i++) { + Object row = result.getRow(i); + sp.put((String) result.getColumnValue(row, 1), (String) result.getColumnValue(row, 2)); + } + future.complete(sp); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ThreadRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ThreadRoute.java new file mode 100644 index 0000000..65b582e --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/ThreadRoute.java
@@ -0,0 +1,198 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.worker.Constant; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import org.eclipse.jifa.worker.vo.heapdump.thread.Info; +import org.eclipse.jifa.worker.vo.heapdump.thread.LocalVariable; +import org.eclipse.jifa.worker.vo.heapdump.thread.StackFrame; +import io.vertx.core.Future; +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.inspections.threads.ThreadOverviewQuery; +import org.eclipse.mat.internal.Messages; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.GCRootInfo; +import org.eclipse.mat.snapshot.model.IObject; +import org.eclipse.mat.snapshot.query.IHeapObjectArgument; +import org.eclipse.mat.util.IProgressListener; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; + +class ThreadRoute extends HeapBaseRoute { + + @RouteMeta(path = "/threadsSummary") + void threadsSummary(Future<Map<String, Long>> future, @ParamKey("file") String file) throws Exception { + + ThreadOverviewQuery query = new ThreadOverviewQuery(); + query.snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + List<?> elements = result.getElements(); + long totalShallowSize = 0; + long totalRetainedSize = 0; + for (Object t : elements) { + totalShallowSize += ((Bytes) result.getColumnValue(t, 2)).getValue(); + totalRetainedSize += ((Bytes) result.getColumnValue(t, 3)).getValue(); + } + Map<String, Long> info = new HashMap<>(); + info.put(Constant.Heap.TOTAL_SIZE_KEY, (long) elements.size()); + info.put(Constant.Heap.SHALLOW_HEAP_KEY, totalShallowSize); + info.put(Constant.Heap.RETAINED_HEAP_KEY, totalRetainedSize); + future.complete(info); + } + + @RouteMeta(path = "/threads") + void threads(Future<PageView<Info>> future, @ParamKey("file") String file, PagingRequest paging) throws Exception { + + ThreadOverviewQuery query = new ThreadOverviewQuery(); + query.snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + List<?> elements = result.getElements(); + + + future.complete(PageViewBuilder.build(elements, paging, e -> new Info(result.getContext(e).getObjectId(), + (String) result.getColumnValue(e, 0), + (String) result.getColumnValue(e, 1), + ((Bytes) result.getColumnValue(e, 2)) + .getValue(), + ((Bytes) result.getColumnValue(e, 3)) + .getValue(), + (String) result.getColumnValue(e, 4), + result.hasChildren(e), + (Boolean) result.getColumnValue(e, 5)))); + } + + private IResultTree fetchStaceTrace(ISnapshot snapshot, int objectId) throws Exception { + ThreadOverviewQuery query = new ThreadOverviewQuery(); + query.snapshot = snapshot; + query.objects = new IHeapObjectArgument() { + @Override + public int[] getIds(IProgressListener iProgressListener) { + throw new UnsupportedOperationException(); + } + + @Override + public String getLabel() { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<int[]> iterator() { + return new Iterator<int[]>() { + + boolean hasNext = true; + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public int[] next() { + ASSERT.isTrue(hasNext); + hasNext = false; + return new int[]{objectId}; + } + }; + } + }; + return (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + } + + @RouteMeta(path = "/stackTrace") + void stackTrace(Future<List<StackFrame>> future, @ParamKey("file") String file, + @ParamKey("objectId") int objectId) throws Exception { + + + IResultTree result = fetchStaceTrace(Analyzer.getOrOpenSnapshotContext(file).getSnapshot(), objectId); + + List<?> elements = result.getElements(); + + if (result.hasChildren(elements.get(0))) { + + List<?> frames = result.getChildren(elements.get(0)); + + List<StackFrame> res = frames.stream().map( + frame -> new StackFrame((String) result.getColumnValue(frame, 0), result.hasChildren(frame))) + .collect(Collectors.toList()); + res.stream().filter(t -> !t.getStack().contains("Native Method")).findFirst() + .ifPresent(sf -> sf.setFirstNonNativeFrame(true)); + future.complete(res); + } else { + future.complete(Collections.emptyList()); + } + } + + @RouteMeta(path = "/locals") + void locals(Future<List<LocalVariable>> future, @ParamKey("file") String file, @ParamKey("objectId") int objectId, + @ParamKey("depth") int depth, + @ParamKey("firstNonNativeFrame") boolean firstNonNativeFrame) throws Exception { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + IResultTree result = fetchStaceTrace(snapshot, objectId); + + List<?> elements = result.getElements(); + if (result.hasChildren(elements.get(0))) { + List<?> frames = result.getChildren(elements.get(0)); + Object frame = frames.get(depth - 1); + if (result.hasChildren(frame)) { + List<?> locals = result.getChildren(frame); + future.complete(locals.stream().map(local -> { + int id = result.getContext(local).getObjectId(); + LocalVariable var = new LocalVariable(); + var.setObjectId(id); + try { + IObject object = snapshot.getObject(id); + var.setLabel(object.getDisplayName()); + var.setShallowSize(object.getUsedHeapSize()); + var.setRetainedSize(object.getRetainedHeapSize()); + var.setObjectType(HeapObject.Type.typeOf(object)); + var.setGCRoot(snapshot.isGCRoot(id)); + var.setHasOutbound(result.hasChildren(var)); + var.setPrefix(Messages.ThreadStackQuery_Label_Local); + if (firstNonNativeFrame) { + GCRootInfo[] gcRootInfos = object.getGCRootInfo(); + if (gcRootInfos != null) { + for (GCRootInfo gcRootInfo : gcRootInfos) { + if (gcRootInfo.getContextId() != 0 && + (gcRootInfo.getType() & GCRootInfo.Type.BUSY_MONITOR) != 0 && + gcRootInfo.getContextId() == objectId) { + var.setPrefix(Messages.ThreadStackQuery_Label_Local_Blocked_On); + } + } + } + } + var.setSuffix(HeapDumpSupport.suffix(snapshot, id)); + return var; + } catch (SnapshotException e) { + throw new JifaException(e); + } + }).collect(Collectors.toList())); + return; + } + } + future.complete(Collections.emptyList()); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/UnreachableObjectsRoute.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/UnreachableObjectsRoute.java new file mode 100644 index 0000000..4f19dc0 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/route/heapdump/UnreachableObjectsRoute.java
@@ -0,0 +1,81 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route.heapdump; + +import org.eclipse.jifa.common.request.PagingRequest; +import org.eclipse.jifa.common.util.PageViewBuilder; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.support.Analyzer; +import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport; +import org.eclipse.jifa.worker.route.ParamKey; +import org.eclipse.jifa.worker.route.RouteMeta; +import org.eclipse.jifa.worker.vo.heapdump.unreachable.Record; +import org.eclipse.jifa.worker.vo.heapdump.unreachable.Summary; +import io.vertx.core.Future; +import org.eclipse.mat.query.Bytes; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.UnreachableObjectsHistogram; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +class UnreachableObjectsRoute extends HeapBaseRoute { + + @RouteMeta(path = "/unreachableObjects/summary") + void summary(Future<Summary> future, @ParamKey("file") String file) { + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + UnreachableObjectsHistogram histogram = (UnreachableObjectsHistogram) snapshot.getSnapshotInfo().getProperty( + UnreachableObjectsHistogram.class.getName()); + + Summary summary = new Summary(); + if (histogram != null) { + summary.setTotalSize(histogram.getRowCount()); + int objects = 0; + long shallowSize = 0; + for (Object record : histogram.getRecords()) { + objects += (Integer) histogram.getColumnValue(record, 1); + shallowSize += ((Bytes) histogram.getColumnValue(record, 2)).getValue(); + } + + summary.setObjects(objects); + summary.setShallowSize(shallowSize); + } + future.complete(summary); + } + + @RouteMeta(path = "/unreachableObjects/records") + void records(Future<PageView<Record>> future, @ParamKey("file") String file, PagingRequest pagingRequest) { + + ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot(); + UnreachableObjectsHistogram histogram = (UnreachableObjectsHistogram) snapshot.getSnapshotInfo().getProperty( + UnreachableObjectsHistogram.class.getName()); + + List<?> total = new ArrayList<>(histogram.getRecords()); + total.sort((Comparator<Object>) (o1, o2) -> { + long v2 = ((Bytes) histogram.getColumnValue(o2, 2)).getValue(); + long v1 = ((Bytes) histogram.getColumnValue(o1, 2)).getValue(); + return Long.compare(v2, v1); + }); + + future.complete(PageViewBuilder.build(total, pagingRequest, record -> { + Record r = new Record(); + r.setClassName((String) histogram.getColumnValue(record, 0)); + r.setObjectId(HeapDumpSupport.fetchObjectId(histogram.getContext(record))); + r.setObjects((Integer) histogram.getColumnValue(record, 1)); + r.setShallowSize(((Bytes) histogram.getColumnValue(record, 2)).getValue()); + return r; + })); + + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/AnalysisProgressListener.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/AnalysisProgressListener.java new file mode 100644 index 0000000..dad633e --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/AnalysisProgressListener.java
@@ -0,0 +1,103 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support; + +import org.eclipse.jifa.worker.Constant; +import org.eclipse.mat.util.IProgressListener; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class AnalysisProgressListener implements IProgressListener { + + private StringBuffer log = new StringBuffer(); + + private int total; + + private int done; + + private String lastSubTask; + + private void append(String msg) { + log.append(msg); + log.append(Constant.LINE_SEPARATOR); + } + + public String log() { + return log.toString(); + } + + @Override + public void beginTask(String s, int i) { + total += i; + append(String.format("[Begin task] %s", s)); + } + + @Override + public void done() { + } + + @Override + public boolean isCanceled() { + return false; + } + + @Override + public void setCanceled(boolean b) { + throw new UnsupportedOperationException(); + } + + @Override + public void subTask(String s) { + if (lastSubTask == null || !lastSubTask.equals(s)) { + lastSubTask = s; + append(String.format("[Sub task] %s", s)); + } + } + + @Override + public void worked(int i) { + done += i; + } + + @Override + public void sendUserMessage(Severity severity, String s, Throwable throwable) { + StringWriter sw = new StringWriter(); + switch (severity) { + case INFO: + sw.append("[INFO] "); + break; + case WARNING: + sw.append("[WARNING] "); + break; + case ERROR: + sw.append("[ERROR] "); + break; + default: + sw.append("[UNKNOWN] "); + } + + sw.append(s); + + if (throwable != null) { + sw.append(Constant.LINE_SEPARATOR); + throwable.printStackTrace(new PrintWriter(sw)); + } + + append(sw.toString()); + } + + public double percent() { + return total == 0 ? 0 : ((double) done) / ((double) total); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/Analyzer.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/Analyzer.java new file mode 100644 index 0000000..2643b48 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/Analyzer.java
@@ -0,0 +1,226 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import io.vertx.core.Future; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.common.util.ErrorUtil; +import org.eclipse.jifa.common.util.FileUtil; +import org.eclipse.jifa.worker.support.heapdump.SnapshotContext; +import org.eclipse.mat.snapshot.SnapshotFactory; +import org.eclipse.mat.util.IProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.jifa.common.enums.FileType.HEAP_DUMP; +import static org.eclipse.jifa.common.util.Assertion.ASSERT; +import static org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport.VOID_LISTENER; + +public class Analyzer { + private static final Logger LOGGER = LoggerFactory.getLogger(Analyzer.class); + + private Map<String, AnalysisProgressListener> listeners; + private Cache<String, Object> cache; + + private Analyzer() { + listeners = new HashMap<>(); + cache = CacheBuilder.newBuilder().build(); + } + + private static <T> T getOrBuild(String key, Builder<T> builder) { + T result = getInstance().getCacheValueIfPresent(key); + if (result != null) { + return result; + } + + synchronized (key.intern()) { + result = getInstance().getCacheValueIfPresent(key); + if (result != null) { + return result; + } + try { + result = builder.build(key); + } catch (Throwable t) { + throw new JifaException(t); + } + getInstance().putCacheValue(key, result); + return result; + } + } + + private static SnapshotContext getOrOpenSnapshotContext(String heapFile, + Map<String, String> option, IProgressListener listener) { + return getOrBuild(heapFile, key -> new SnapshotContext( + SnapshotFactory.openSnapshot(new File(FileSupport.filePath(HEAP_DUMP, heapFile)), option, + listener))); + } + + public static SnapshotContext getOrOpenSnapshotContext(String heapFile) { + return getOrOpenSnapshotContext(heapFile, Collections.emptyMap(), VOID_LISTENER); + } + + public static Analyzer getInstance() { + return Singleton.INSTANCE; + } + + public boolean isFirstAnalysis(FileType fileType, String file) { + switch (fileType) { + case HEAP_DUMP: + return !new File(FileSupport.indexPath(fileType, file)).exists() && + !new File(FileSupport.errorLogPath(fileType, file)).exists() && + getFileListener(file) == null; + default: + throw new IllegalArgumentException(fileType.name()); + } + } + + public void analyze(Future<Void> future, FileType fileType, String fileName, Map<String, String> options) { + AnalysisProgressListener progressListener; + + if (getCacheValueIfPresent(fileName) != null || + new File(FileSupport.errorLogPath(fileType, fileName)).exists()) { + future.complete(); + return; + } + + progressListener = new AnalysisProgressListener(); + boolean success = putFileListener(fileName, progressListener); + future.complete(); + + if (success) { + try { + switch (fileType) { + case HEAP_DUMP: + getOrOpenSnapshotContext(fileName, options, progressListener); + break; + default: + break; + } + } catch (Exception e) { + File log = new File(FileSupport.errorLogPath(fileType, fileName)); + FileUtil.write(log, progressListener.log(), false); + FileUtil.write(log, ErrorUtil.toString(e), true); + } finally { + removeFileListener(fileName); + } + } + } + + public void clean(FileType fileType, String fileName) { + clearCacheValue(fileName); + + File errorLog = new File(FileSupport.errorLogPath(fileType, fileName)); + if (errorLog.exists()) { + ASSERT.isTrue(errorLog.delete(), "Delete error log failed"); + } + + if (getFileListener(fileName) != null) { + return; + } + + File index = new File(FileSupport.indexPath(fileType, fileName)); + if (index.exists()) { + ASSERT.isTrue(index.delete(), "Delete index file failed"); + } + } + + public void release(String fileName) { + clearCacheValue(fileName); + } + + public org.eclipse.jifa.common.vo.Progress pollProgress(FileType fileType, String fileName) { + AnalysisProgressListener progressListener = getFileListener(fileName); + + if (progressListener == null) { + org.eclipse.jifa.common.vo.Progress progress = buildProgressIfFinished(fileType, fileName); + ASSERT.notNull(progress); + return progress; + } else { + org.eclipse.jifa.common.vo.Progress progress = new org.eclipse.jifa.common.vo.Progress(); + progress.setState(ProgressState.IN_PROGRESS); + progress.setMessage(progressListener.log()); + progress.setPercent(progressListener.percent()); + return progress; + } + } + + @SuppressWarnings("unchecked") + private synchronized <T> T getCacheValueIfPresent(String key) { + return (T) cache.getIfPresent(key); + } + + private synchronized void putCacheValue(String key, Object value) { + cache.put(key, value); + LOGGER.info("Put cache: {}", key); + } + + private synchronized void clearCacheValue(String key) { + Object value = cache.getIfPresent(key); + if (value instanceof SnapshotContext) { + SnapshotFactory.dispose(((SnapshotContext) value).getSnapshot()); + } + cache.invalidate(key); + LOGGER.info("Clear cache: {}", key); + } + + private synchronized AnalysisProgressListener getFileListener(String fileName) { + return listeners.get(fileName); + } + + private synchronized boolean putFileListener(String fileName, AnalysisProgressListener listener) { + if (listeners.containsKey(fileName)) { + return false; + } + listeners.put(fileName, listener); + return true; + } + + private synchronized void removeFileListener(String fileName) { + listeners.remove(fileName); + } + + private org.eclipse.jifa.common.vo.Progress buildProgressIfFinished(FileType fileType, String fileName) { + if (getCacheValueIfPresent(fileName) != null) { + org.eclipse.jifa.common.vo.Progress result = new org.eclipse.jifa.common.vo.Progress(); + result.setPercent(1); + result.setState(ProgressState.SUCCESS); + return result; + } + + File failed = new File(FileSupport.errorLogPath(fileType, fileName)); + if (failed.exists()) { + org.eclipse.jifa.common.vo.Progress result = new org.eclipse.jifa.common.vo.Progress(); + result.setState(ProgressState.ERROR); + result.setMessage(FileUtil.content(failed)); + return result; + } + return null; + } + + interface Builder<T> { + T build(String key) throws Throwable; + } + + private static class Singleton { + static Analyzer INSTANCE = new Analyzer(); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/BinFunction.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/BinFunction.java new file mode 100644 index 0000000..fff47a4 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/BinFunction.java
@@ -0,0 +1,17 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support; + +public interface BinFunction<A, B, R> { + R apply(A a, B b) throws Exception; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/FileSupport.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/FileSupport.java new file mode 100644 index 0000000..bdc9727 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/FileSupport.java
@@ -0,0 +1,412 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support; + +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.event.ProgressEventType; +import com.aliyun.oss.model.DownloadFileRequest; +import com.aliyun.oss.model.ObjectMetadata; +import io.vertx.core.Future; +import net.schmizz.sshj.SSHClient; +import net.schmizz.sshj.common.StreamCopier; +import net.schmizz.sshj.xfer.FileSystemFile; +import net.schmizz.sshj.xfer.scp.SCPDownloadClient; +import net.schmizz.sshj.xfer.scp.SCPFileTransfer; +import org.apache.commons.io.FileUtils; +import org.eclipse.jifa.common.aux.ErrorCode; +import org.eclipse.jifa.common.aux.JifaException; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.common.util.FileUtil; +import org.eclipse.jifa.common.vo.FileInfo; +import org.eclipse.jifa.common.vo.TransferringFile; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.worker.support.heapdump.TransferListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.eclipse.jifa.common.util.Assertion.ASSERT; +import static org.eclipse.jifa.common.util.GsonHolder.GSON; +import static org.eclipse.jifa.worker.Constant.File.INFO_FILE_SUFFIX; + +public class FileSupport { + + public static final List<String> PUB_KEYS = new ArrayList<>(); + + private static final String ERROR_LOG = "error.log"; + + private static final Logger LOGGER = LoggerFactory.getLogger(FileSupport.class); + + private static final Map<String, TransferListener> transferListeners = new ConcurrentHashMap<>(); + + private static String[] keyLocations() { + final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator; + return new String[]{base + "jifa-ssh-key"}; + } + + private static String[] pubKeyLocations() { + final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator; + return new String[]{base + "jifa-ssh-key.pub"}; + } + + public static void init() { + for (FileType type : FileType.values()) { + File file = new File(Global.workspace() + File.separator + type.getTag()); + if (file.exists()) { + ASSERT.isTrue(file.isDirectory(), String.format("%s must be directory", file.getAbsolutePath())); + } else { + ASSERT.isTrue(file.mkdirs(), String.format("Can not create %s ", file.getAbsolutePath())); + } + } + + for (String loc : pubKeyLocations()) { + File f = new File(loc); + if (f.exists() && f.length() > 0) { + PUB_KEYS.add(FileUtil.content(f)); + } + } + } + + public static void initInfoFile(FileType type, String originalName, String name) { + ASSERT.isTrue(new File(dirPath(type, name)).mkdirs(), "Make directory failed"); + + FileInfo info = buildInitFileInfo(type, originalName, name); + try { + FileUtils.write(infoFile(type, name), GSON.toJson(info), Charset.defaultCharset()); + } catch (IOException e) { + LOGGER.error("Write file information failed", e); + throw new JifaException(e); + } + } + + private static FileInfo buildInitFileInfo(FileType type, String originalName, String name) { + FileInfo info = new FileInfo(); + info.setOriginalName(originalName); + info.setName(name); + info.setSize(0); + info.setType(type); + info.setTransferState(ProgressState.NOT_STARTED); + info.setDownloadable(false); + info.setCreationTime(System.currentTimeMillis()); + return info; + } + + public static List<FileInfo> info(FileType type) { + List<FileInfo> infoList = new ArrayList<>(); + File dir = new File(dirPath(type)); + ASSERT.isTrue(dir.isDirectory(), ErrorCode.SANITY_CHECK); + + File[] subDirs = dir.listFiles(File::isDirectory); + if (subDirs == null) { + return infoList; + } + + for (File subDir : subDirs) { + String infoFileName = subDir.getName() + INFO_FILE_SUFFIX; + File[] files = subDir.listFiles((d, name) -> infoFileName.equals(name)); + if (files != null && files.length == 1) { + File infoFile = files[0]; + try { + FileInfo info = GSON.fromJson(FileUtils.readFileToString(infoFile, Charset.defaultCharset()), + FileInfo.class); + ensureValidFileInfo(info); + infoList.add(info); + } catch (Exception e) { + LOGGER.error("Read file information failed: {}", infoFile.getAbsolutePath(), e); + // should not throw exception here + } + } + } + return infoList; + } + + private static void ensureValidFileInfo(FileInfo info) { + ASSERT.notNull(info) + .notNull(info.getOriginalName()) + .notNull(info.getName()) + .notNull(info.getType()) + .notNull(info.getTransferState()) + .isTrue(info.getSize() >= 0) + .isTrue(info.getCreationTime() > 0); + } + + public static FileInfo getOrGenInfo(FileType type, String name) { + File file = new File(FileSupport.filePath(type, name)); + ASSERT.isTrue(file.exists(), ErrorCode.FILE_DOES_NOT_EXIST); + + File infoFile = infoFile(type, name); + if (infoFile.exists()) { + return info(type, name); + } + + FileInfo fileInfo = buildInitFileInfo(type, name, name); + fileInfo.setCreationTime(file.lastModified()); + fileInfo.setTransferState(ProgressState.SUCCESS); + fileInfo.setSize(file.length()); + save(fileInfo); + return fileInfo; + } + + public static FileInfo info(FileType type, String name) { + File infoFile = infoFile(type, name); + FileInfo fileInfo; + try { + fileInfo = GSON.fromJson(FileUtils.readFileToString(infoFile, Charset.defaultCharset()), FileInfo.class); + ensureValidFileInfo(fileInfo); + } catch (IOException e) { + LOGGER.error("Read file information failed", e); + throw new JifaException(e); + } + return fileInfo; + } + + public static void save(FileInfo info) { + try { + FileUtils + .write(infoFile(info.getType(), info.getName()), GSON.toJson(info), Charset.defaultCharset()); + } catch (IOException e) { + LOGGER.error("Save file information failed", e); + throw new JifaException(e); + } + } + + public static void delete(FileType type, String name) { + try { + FileUtils.deleteDirectory(new File(dirPath(type, name))); + } catch (IOException e) { + LOGGER.error("Delete file failed", e); + throw new JifaException(e); + } + } + + public static void updateTransferState(FileType type, String name, ProgressState state) { + FileInfo info = info(type, name); + info.setTransferState(state); + if (state == ProgressState.SUCCESS) { + // for worker, file is downloadable after transferred + info.setSize(new File(FileSupport.filePath(type, name)).length()); + info.setDownloadable(true); + } + save(info); + } + + private static String dirPath(FileType type) { + return Global.workspace() + File.separator + type.getTag(); + } + + public static String dirPath(FileType type, String name) { + return dirPath(type) + File.separator + name; + } + + private static String infoFilePath(FileType type, String name) { + return dirPath(type, name) + File.separator + name + INFO_FILE_SUFFIX; + } + + private static File infoFile(FileType type, String name) { + return new File(infoFilePath(type, name)); + } + + public static String filePath(FileType type, String name) { + return filePath(type, name, name); + } + + private static String filePath(FileType type, String name, String childrenName) { + return dirPath(type, name) + File.separator + childrenName; + } + + public static String errorLogPath(FileType fileType, String file) { + return FileSupport.filePath(fileType, file, ERROR_LOG); + } + + public static String indexPath(FileType fileType, String file) { + String indexFileNamePrefix; + int i = file.lastIndexOf('.'); + if (i >= 0) { + indexFileNamePrefix = file.substring(0, i + 1); + } else { + indexFileNamePrefix = file + '.'; + } + return FileSupport.filePath(fileType, file, indexFileNamePrefix + "index"); + } + + public static TransferListener createTransferListener(FileType fileType, String originalName, String fileName) { + TransferListener listener = new TransferListener(fileType, originalName, fileName); + transferListeners.put(fileName, listener); + return listener; + } + + public static void removeTransferListener(String fileName) { + transferListeners.remove(fileName); + } + + public static TransferListener getTransferListener(String fileName) { + return transferListeners.get(fileName); + } + + public static void transferBySCP(String user, String hostname, String src, FileType fileType, String fileName, + TransferListener transferProgressListener, Future<TransferringFile> future) { + transferBySCP(user, null, hostname, src, fileType, fileName, transferProgressListener, future); + } + + public static void transferBySCP(String user, String pwd, String hostname, String src, FileType fileType, + String fileName, TransferListener transferProgressListener, + Future<TransferringFile> future) { + transferProgressListener.updateState(ProgressState.IN_PROGRESS); + SSHClient ssh = new SSHClient(); + ssh.addHostKeyVerifier((h, port, key) -> true); + try { + ssh.connect(hostname); + if (pwd != null) { + ssh.authPassword(user, pwd); + } else { + ssh.authPublickey(user, keyLocations()); + } + SCPFileTransfer transfer = ssh.newSCPFileTransfer(); + transfer.setTransferListener(new net.schmizz.sshj.xfer.TransferListener() { + @Override + public net.schmizz.sshj.xfer.TransferListener directory(String name) { + return this; + } + + @Override + public StreamCopier.Listener file(String name, long size) { + transferProgressListener.setTotalSize(size); + return transferProgressListener::setTransferredSize; + } + }); + SCPDownloadClient downloadClient = transfer.newSCPDownloadClient(); + future.complete(new TransferringFile(fileName)); + // do not copy dir now + downloadClient.setRecursiveMode(false); + downloadClient.copy(src, new FileSystemFile(FileSupport.filePath(fileType, fileName))); + transferProgressListener.updateState(ProgressState.SUCCESS); + } catch (Exception e) { + LOGGER.error("SSH transfer failed"); + handleTransferError(fileName, transferProgressListener, future, e); + } finally { + try { + ssh.disconnect(); + } catch (IOException e) { + LOGGER.error("SSH disconnect failed", e); + } + } + } + + public static void transferByURL(String url, FileType fileType, String fileName, TransferListener listener, + Future<TransferringFile> future) { + InputStream in = null; + OutputStream out = null; + String filePath = FileSupport.filePath(fileType, fileName); + try { + URLConnection conn = new URL(url).openConnection(); + listener.updateState(ProgressState.IN_PROGRESS); + future.complete(new TransferringFile(fileName)); + listener.setTotalSize(conn.getContentLength()); + in = conn.getInputStream(); + out = new FileOutputStream(filePath); + byte[] buffer = new byte[8192]; + int length; + while ((length = in.read(buffer)) > 0) { + out.write(buffer, 0, length); + listener.addTransferredSize(length); + } + listener.updateState(ProgressState.SUCCESS); + } catch (Exception e) { + LOGGER.error("URL transfer failed"); + handleTransferError(fileName, listener, future, e); + } finally { + try { + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } catch (IOException e) { + LOGGER.error("Close stream failed", e); + } + } + } + + public static void transferByOSS(String endpoint, String accessKeyId, String accessKeySecret, String bucketName, + String objectName, FileType fileType, String fileName, + TransferListener transferProgressListener, + Future<TransferringFile> future) { + OSSClient ossClient = null; + try { + ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); + + ObjectMetadata meta = ossClient.getObjectMetadata(bucketName, objectName); + transferProgressListener.setTotalSize(meta.getContentLength()); + future.complete(new TransferringFile(fileName)); + + DownloadFileRequest downloadFileRequest = new DownloadFileRequest(bucketName, objectName); + downloadFileRequest.setDownloadFile(new File(FileSupport.filePath(fileType, fileName)).getAbsolutePath()); + // 128m per thread now + downloadFileRequest.setPartSize(128 * 1024 * 1024); + downloadFileRequest.setTaskNum(Runtime.getRuntime().availableProcessors()); + downloadFileRequest.setEnableCheckpoint(true); + downloadFileRequest.withProgressListener(progressEvent -> { + long bytes = progressEvent.getBytes(); + ProgressEventType eventType = progressEvent.getEventType(); + switch (eventType) { + case TRANSFER_STARTED_EVENT: + transferProgressListener.updateState(ProgressState.IN_PROGRESS); + break; + case RESPONSE_BYTE_TRANSFER_EVENT: + transferProgressListener.addTransferredSize(bytes); + break; + case TRANSFER_FAILED_EVENT: + transferProgressListener.updateState(ProgressState.ERROR); + break; + default: + break; + } + }); + ossClient.downloadFile(downloadFileRequest); + transferProgressListener.updateState(ProgressState.SUCCESS); + } catch (Throwable t) { + LOGGER.error("OSS transfer failed"); + handleTransferError(fileName, transferProgressListener, future, t); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + } + + private static void handleTransferError(String fileName, TransferListener transferProgressListener, + Future<TransferringFile> future, Throwable t) { + if (future.isComplete()) { + transferProgressListener.updateState(ProgressState.ERROR); + Throwable cause = t; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + transferProgressListener.setErrorMsg(cause.toString()); + } else { + FileSupport.delete(transferProgressListener.getFileType(), fileName); + removeTransferListener(fileName); + } + throw new JifaException(ErrorCode.TRANSFER_ERROR, t); + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/HeapDumpSupport.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/HeapDumpSupport.java new file mode 100644 index 0000000..3c069b8 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/HeapDumpSupport.java
@@ -0,0 +1,85 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support.heapdump; + +import org.eclipse.mat.SnapshotException; +import org.eclipse.mat.query.IContextObject; +import org.eclipse.mat.snapshot.ISnapshot; +import org.eclipse.mat.snapshot.model.GCRootInfo; +import org.eclipse.mat.snapshot.model.IObject; +import org.eclipse.mat.snapshot.model.NamedReference; +import org.eclipse.mat.snapshot.query.IHeapObjectArgument; +import org.eclipse.mat.util.IProgressListener; +import org.eclipse.mat.util.VoidProgressListener; + +import java.util.Iterator; +import java.util.List; + +import static org.eclipse.jifa.common.Constant.EMPTY_STRING; + +public class HeapDumpSupport { + public static final int ILLEGAL_OBJECT_ID = -1; + + public static IProgressListener VOID_LISTENER = new VoidProgressListener(); + + public static int fetchObjectId(IContextObject context) { + return context == null ? ILLEGAL_OBJECT_ID : context.getObjectId(); + } + + public static String suffix(ISnapshot snapshot, int objectId) throws SnapshotException { + GCRootInfo[] gc = snapshot.getGCRootInfo(objectId); + return gc != null ? GCRootInfo.getTypeSetAsString(gc) : EMPTY_STRING; + } + + public static String suffix(GCRootInfo[] gcRootInfo) { + return gcRootInfo != null ? GCRootInfo.getTypeSetAsString(gcRootInfo) : EMPTY_STRING; + } + + public static String prefix(ISnapshot snapshot, int objectId, int outbound) throws SnapshotException { + IObject object = snapshot.getObject(objectId); + + long address = snapshot.mapIdToAddress(outbound); + + StringBuilder s = new StringBuilder(64); + + List<NamedReference> refs = object.getOutboundReferences(); + for (NamedReference reference : refs) { + if (reference.getObjectAddress() == address) { + if (s.length() > 0) { + s.append(", "); + } + s.append(reference.getName()); + } + } + return s.toString(); + } + + public static IHeapObjectArgument buildHeapObjectArgument(int[] ids) { + return new IHeapObjectArgument() { + @Override + public int[] getIds(IProgressListener iProgressListener) { + return ids; + } + + @Override + public String getLabel() { + return null; + } + + @Override + public Iterator<int[]> iterator() { + return null; + } + }; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/SnapshotContext.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/SnapshotContext.java new file mode 100644 index 0000000..7735103 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/SnapshotContext.java
@@ -0,0 +1,199 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support.heapdump; + +import lombok.Data; +import org.eclipse.mat.inspections.ClassLoaderExplorerQuery; +import org.eclipse.mat.inspections.LeakHunterQuery; +import org.eclipse.mat.inspections.OQLQuery; +import org.eclipse.mat.internal.snapshot.SnapshotQueryContext; +import org.eclipse.mat.internal.snapshot.inspections.OldObjRefYoungObjQuery; +import org.eclipse.mat.query.Column; +import org.eclipse.mat.query.IResult; +import org.eclipse.mat.query.IResultTable; +import org.eclipse.mat.query.IResultTree; +import org.eclipse.mat.query.refined.RefinedResultBuilder; +import org.eclipse.mat.query.refined.RefinedTable; +import org.eclipse.mat.snapshot.ISnapshot; + +import java.lang.ref.SoftReference; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SnapshotContext { + + private ISnapshot snapshot; + + private SoftReference<DirectByteBuffer> directByteBuffer; + private SoftReference<ClassLoaderExplorer> classLoaderExplorer; + private SoftReference<LeakReport> leakReport; + + public SnapshotContext(ISnapshot snapshot) { + this.snapshot = snapshot; + } + + private synchronized <T> T fetch(SoftReference<T> cache, Builder<T> builder) throws Exception { + T res; + if (cache == null || (res = cache.get()) == null) { + res = builder.build(); + } + return res; + } + + public synchronized ClassLoaderExplorer classLoaderExplorer() throws Exception { + return fetch(classLoaderExplorer, () -> { + ClassLoaderExplorer result = new ClassLoaderExplorer(); + classLoaderExplorer = new SoftReference<>(result); + return result; + }); + } + + public synchronized DirectByteBuffer directByteBuffer() throws Exception { + return fetch(directByteBuffer, () -> { + DirectByteBuffer result = new DirectByteBuffer(); + directByteBuffer = new SoftReference<>(result); + return result; + }); + } + + public synchronized LeakReport leakReport() throws Exception { + return fetch(leakReport, () -> { + LeakReport result = new LeakReport(); + leakReport = new SoftReference<>(result); + return result; + }); + } + + public ISnapshot getSnapshot() { + return snapshot; + } + + interface Builder<T> { + T build() throws Exception; + } + + @Data + public class LeakReport { + IResult result; + + LeakReport() throws Exception { + LeakHunterQuery query = new LeakHunterQuery(); + query.snapshot = snapshot; + result = query.execute(HeapDumpSupport.VOID_LISTENER); + } + } + + @Data + public class DirectByteBuffer { + private static final String OQL = + "SELECT s.@displayName as label, s.position as position, s.limit as limit, s.capacity as " + + "capacity FROM java.nio.DirectByteBuffer s where s.cleaner != null"; + RefinedTable resultContext; + private long position; + private long limit; + private long capacity; + private int totalSize; + + DirectByteBuffer() throws Exception { + OQLQuery query = new OQLQuery(); + query.snapshot = snapshot; + query.queryString = OQL; + IResult result = query.execute(HeapDumpSupport.VOID_LISTENER); + if (result instanceof IResultTable) { + RefinedResultBuilder builder = + new RefinedResultBuilder(new SnapshotQueryContext(snapshot), (IResultTable) result); + builder.setSortOrder(3, Column.SortDirection.DESC); + resultContext = (RefinedTable) builder.build(); + totalSize = resultContext.getRowCount(); + for (int i = 0; i < totalSize; i++) { + Object row = resultContext.getRow(i); + position += position(row); + limit += limit(row); + capacity += capacity(row); + } + } + + } + + public String label(Object row) { + return (String) resultContext.getColumnValue(row, 0); + } + + public int position(Object row) { + return (Integer) resultContext.getColumnValue(row, 1); + } + + public int limit(Object row) { + return (Integer) resultContext.getColumnValue(row, 2); + } + + public int capacity(Object row) { + return (Integer) resultContext.getColumnValue(row, 3); + } + + } + + @Data + public class OldObjRefYoungObj { + private OldObjRefYoungObjQuery.Tree result; + private List<?> records; + private int refCount; + + OldObjRefYoungObj() throws Exception { + OldObjRefYoungObjQuery query = new OldObjRefYoungObjQuery(); + query.snapshot = snapshot; + query.groupBy = OldObjRefYoungObjQuery.Grouping.BY_CLASS; + result = query.execute(HeapDumpSupport.VOID_LISTENER); + records = result.getElements(); + for (Object record : records) { + refCount += (int) result.getColumnValue(record, 1); + } + } + } + + @Data + public class ClassLoaderExplorer { + private IResult resultContext; + + // classloader object Id -> record + private Map<Integer, Object> classLoaderIdMap; + + private List<?> records; + + private int definedClasses; + + private int numberOfInstances; + + ClassLoaderExplorer() throws Exception { + ClassLoaderExplorerQuery query = new ClassLoaderExplorerQuery(); + query.snapshot = snapshot; + IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER); + this.resultContext = result; + Map<Integer, Object> classLoaderIdMap = new HashMap<>(); + for (Object r : result.getElements()) { + classLoaderIdMap.put(result.getContext(r).getObjectId(), r); + } + this.records = result.getElements(); + this.records.sort((Comparator<Object>) (o1, o2) -> Integer + .compare((int) result.getColumnValue(o2, 1), (int) result.getColumnValue(o1, 1))); + this.classLoaderIdMap = classLoaderIdMap; + + for (Object record : records) { + definedClasses += (int) result.getColumnValue(record, 1); + numberOfInstances += (int) result.getColumnValue(record, 2); + } + } + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/TransferListener.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/TransferListener.java new file mode 100644 index 0000000..60f28b9 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/support/heapdump/TransferListener.java
@@ -0,0 +1,62 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.support.heapdump; + +import lombok.Data; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.worker.support.FileSupport; + +@Data +public class TransferListener { + + private ProgressState state; + private long totalSize; + private long transferredSize; + private String errorMsg; + + private FileType fileType; + private String fileName; + + public TransferListener(FileType fileType, String originalName, String fileName) { + this.fileType = fileType; + this.fileName = fileName; + this.state = ProgressState.NOT_STARTED; + FileSupport.initInfoFile(fileType, originalName, fileName); + } + + public synchronized void updateState(ProgressState state) { + if (this.state == state) { + return; + } + + if (state == ProgressState.SUCCESS) { + FileSupport.updateTransferState(fileType, fileName, ProgressState.SUCCESS); + totalSize = FileSupport.info(fileType, fileName).getSize(); + } + + if (state == ProgressState.ERROR) { + FileSupport.updateTransferState(fileType, fileName, ProgressState.ERROR); + } + + if (state == ProgressState.IN_PROGRESS && this.state == ProgressState.NOT_STARTED) { + FileSupport.updateTransferState(fileType, fileName, ProgressState.IN_PROGRESS); + } + + this.state = state; + } + + public synchronized void addTransferredSize(long bytes) { + this.transferredSize += bytes; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/HeapObject.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/HeapObject.java new file mode 100644 index 0000000..c42c7d5 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/HeapObject.java
@@ -0,0 +1,57 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump; + +import lombok.Data; +import org.eclipse.mat.snapshot.model.IClass; +import org.eclipse.mat.snapshot.model.IClassLoader; +import org.eclipse.mat.snapshot.model.IObject; + +@Data +public class HeapObject { + private int objectId; + private String prefix; + private String label; + private String suffix; + private long shallowSize; + private long retainedSize; + private boolean hasInbound; + private boolean hasOutbound; + private int objectType; + private boolean gCRoot; + + public static class Type { + + static final int CLASS = 1; + static final int CLASS_LOADER = 2; + static final int ARRAY = 3; + static final int NORMAL = 4; + + public static int typeOf(IObject object) { + if (object instanceof IClass) { + return CLASS; + } + + if (object instanceof IClassLoader) { + return CLASS_LOADER; + } + + if (object.getClazz().isArrayType()) { + return ARRAY; + } + return NORMAL; + } + } +} + +
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Record.java new file mode 100644 index 0000000..328d65d --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Record.java
@@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.classloader; + +import lombok.Data; + +@Data +public class Record { + + private int objectId; + + private String prefix; + + private String label; + + private boolean classLoader; + + private boolean hasParent; + + private int definedClasses; + + private int numberOfInstances; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Summary.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Summary.java new file mode 100644 index 0000000..1e84862 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classloader/Summary.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.classloader; + +import lombok.Data; + +@Data +public class Summary { + + private int totalSize; + + private int definedClasses; + + private int numberOfInstances; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classreference/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classreference/Record.java new file mode 100644 index 0000000..ea08de8 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/classreference/Record.java
@@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.classreference; + +import lombok.Data; + +@Data +public class Record { + + private String label; + + private int objects; + + private long shallowSize; + + private int objectId; + + private int[] objectIds; + + private int type; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Record.java new file mode 100644 index 0000000..5020c1f --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Record.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.compare; + +import lombok.Data; + +@Data +public class Record { + + private String className; + + private long objects; + + private long shallowSize; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Summary.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Summary.java new file mode 100644 index 0000000..252fd63 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/compare/Summary.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.compare; + +import lombok.Data; + +@Data +public class Summary { + + private int totalSize; + + private long objects; + + private long shallowSize; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Record.java new file mode 100644 index 0000000..e063652 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Record.java
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.directbytebuffer; + +import lombok.Data; + +@Data +public class Record { + + private int objectId; + + private String label; + + private int position; + + private int limit; + + private int capacity; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Summary.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Summary.java new file mode 100644 index 0000000..2641e82 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/directbytebuffer/Summary.java
@@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.directbytebuffer; + +import lombok.Data; + +@Data +public class Summary { + + private int totalSize; + + private long position; + + private long limit; + + private long capacity; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/BaseRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/BaseRecord.java new file mode 100644 index 0000000..3afc504 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/BaseRecord.java
@@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.dominatortree; + +import lombok.Data; + +@Data +public class BaseRecord { + + private String label; + + private String suffix; + + private int objectId; + + private int objectType; + + private boolean gCRoot; + + private long shallowSize; + + private long retainedSize; + + private double percent; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassLoaderRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassLoaderRecord.java new file mode 100644 index 0000000..885e924 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassLoaderRecord.java
@@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.dominatortree; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ClassLoaderRecord extends BaseRecord { + private long objects; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassRecord.java new file mode 100644 index 0000000..7d9a848 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/ClassRecord.java
@@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.dominatortree; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ClassRecord extends BaseRecord { + private int objects; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/DefaultRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/DefaultRecord.java new file mode 100644 index 0000000..d068f99 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/DefaultRecord.java
@@ -0,0 +1,21 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.dominatortree; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class DefaultRecord extends BaseRecord { +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/PackageRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/PackageRecord.java new file mode 100644 index 0000000..186ea1d --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/dominatortree/PackageRecord.java
@@ -0,0 +1,20 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.dominatortree; + +import lombok.Data; + +@Data +public class PackageRecord { + private long objects; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassLoaderRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassLoaderRecord.java new file mode 100644 index 0000000..55cc64f --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassLoaderRecord.java
@@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.duplicatedclass; + +import lombok.Data; + +@Data +public class ClassLoaderRecord { + + private String label; + + private String suffix; + + private int definedClassesCount; + + private int instantiatedObjectsCount; + + private int objectId; + + private boolean gCRoot; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassRecord.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassRecord.java new file mode 100644 index 0000000..2487302 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/duplicatedclass/ClassRecord.java
@@ -0,0 +1,23 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.duplicatedclass; + +import lombok.Data; + +@Data +public class ClassRecord { + + private String label; + + private int count; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcroot/Result.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcroot/Result.java new file mode 100644 index 0000000..b163911 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcroot/Result.java
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.gcroot; + +import lombok.Data; + +@Data +public class Result { + + private String className; + + private int objects; + + private int objectId; + + private long shallowSize; + + private long retainedSize; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcrootpath/Result.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcrootpath/Result.java new file mode 100644 index 0000000..86e8dee --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/gcrootpath/Result.java
@@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.gcrootpath; + +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class Result { + + private Node tree; + private int count; + private boolean hasMore; + + @Data + @EqualsAndHashCode(callSuper = true) + public static class Node extends HeapObject { + + private boolean origin; + + private List<Node> children = new ArrayList<>(); + + public void addChild(Node child) { + children.add(child); + } + + public Node getChild(int objectId) { + for (Node child : children) { + if (child.getObjectId() == objectId) { + return child; + } + } + return null; + } + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/histogram/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/histogram/Record.java new file mode 100644 index 0000000..0ba0902 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/histogram/Record.java
@@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.histogram; + +import lombok.Data; + +@Data +public class Record { + private long numberOfObjects; + private long shallowSize; + private long numberOfYoungObjects; + private long shallowSizeOfYoung; + private long numberOfOldObjects; + private long shallowSizeOfOld; + private long retainedSize; + private String label; + private int objectId; + + private int type; + + public Record(int objectId, String label, int type, long numberOfObjects, long shallowSize, long retainedSize, + long numberOfYoungObjects, long shallowSizeOfYoung, long numberOfOldObjects, long shallowSizeOfOld) { + this.objectId = objectId; + this.label = label; + this.type = type; + this.numberOfObjects = numberOfObjects; + this.shallowSize = shallowSize; + this.retainedSize = retainedSize; + + this.numberOfYoungObjects = numberOfYoungObjects; + this.shallowSizeOfYoung = shallowSizeOfYoung; + this.numberOfOldObjects = numberOfOldObjects; + this.shallowSizeOfOld = shallowSizeOfOld; + } + + public static class Type { + public static int CLASS = 1; + public static int SUPER_CLASS = 2; + public static int CLASS_LOADER = 3; + public static int PACKAGE = 4; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/FieldView.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/FieldView.java new file mode 100644 index 0000000..b32b24e --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/FieldView.java
@@ -0,0 +1,45 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.inspector; + +import lombok.Data; + +@Data +public class FieldView { + + /** + * @see org.eclipse.mat.snapshot.model.IObject.Type + */ + private int fieldType; + + private String name; + + private String value; + + private int objectId; + + public FieldView(int fieldType, String name, String value) { + this.fieldType = fieldType; + this.name = name; + this.value = value; + } + + public FieldView(int fieldType, String name, String value, int objectId) { + this(fieldType, name, value); + this.objectId = objectId; + } + + public FieldView() { + + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/ObjectView.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/ObjectView.java new file mode 100644 index 0000000..0a1d9ea --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/inspector/ObjectView.java
@@ -0,0 +1,63 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.inspector; + +import lombok.Data; +import org.eclipse.mat.snapshot.model.HeapLayout; + +@Data +public class ObjectView { + + private long objectAddress; + + /** + * for non-class object, name = the name of object's class + * for class object, name = class name + */ + private String name; + + private boolean gCRoot; + + private int objectType; + + private String classLabel; + + private boolean classGCRoot; + + private String superClassName; + + private String classLoaderLabel; + + private boolean classLoaderGCRoot; + + private long shallowSize; + + private long retainedSize; + + private String gcRootInfo; + + private int locationType; + + private static final int YOUNG = 1; + private static final int OLD = 2; + private static final int OTHER = 0; + + public static int locationTypeOf(HeapLayout.Generation gen) { + if (gen == HeapLayout.Generation.YOUNG) { + return YOUNG; + } else if (gen == HeapLayout.Generation.OLD) { + return OLD; + } + return OTHER; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/leak/Report.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/leak/Report.java new file mode 100644 index 0000000..a22a277 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/leak/Report.java
@@ -0,0 +1,81 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.leak; + +import lombok.Data; + +import java.util.List; + +@Data +public class Report { + + private boolean useful; + + private String info; + + private String name; + + private List<Slice> slices; + + private List<Record> records; + + @Data + public static class Slice { + + private String label; + + private int objectId; + + private double value; + + private String desc; + + public Slice(String label, int objectId, double value, String desc) { + this.label = label; + this.objectId = objectId; + this.value = value; + this.desc = desc; + } + } + + @Data + public static class Record { + + private String name; + + private String desc; + + private int index; + + private List<ShortestPath> paths; + } + + @Data + public static class ShortestPath { + + private String label; + + private long shallowSize; + + private long retainedSize; + + private int objectId; + + private int objectType; + + private boolean gCRoot; + + private List<ShortestPath> children; + } +} +
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/OQLResult.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/OQLResult.java new file mode 100644 index 0000000..ec896a3 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/OQLResult.java
@@ -0,0 +1,21 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.oql; + +interface OQLResult { + int TREE = 1; + int TABLE = 2; + int TEXT = 3; + + int getType(); +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TableResult.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TableResult.java new file mode 100644 index 0000000..6b53b53 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TableResult.java
@@ -0,0 +1,45 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.oql; + +import org.eclipse.jifa.common.vo.PageView; +import lombok.Data; + +import java.util.List; + +@Data +public class TableResult implements OQLResult { + private int type = TABLE; + + private List<String> columns; + + private PageView<Entry> pv; + + public TableResult(List<String> columns, PageView<Entry> pv) { + this.columns = columns; + this.pv = pv; + } + + @Data + public static class Entry { + + private int objectId; + + private List<Object> values; + + public Entry(int objectId, List<Object> values) { + this.objectId = objectId; + this.values = values; + } + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TextResult.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TextResult.java new file mode 100644 index 0000000..3eb067c --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TextResult.java
@@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.oql; + +import lombok.Data; + +@Data +public class TextResult implements OQLResult { + private int type = OQLResult.TEXT; + + private String text; + + public TextResult(String text) { + this.text = text; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TreeResult.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TreeResult.java new file mode 100644 index 0000000..1589767 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/oql/TreeResult.java
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.oql; + +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import lombok.Data; + +@Data +public class TreeResult implements OQLResult { + + PageView<HeapObject> pv; + + private int type = TREE; + + public TreeResult(PageView<HeapObject> pv) { + this.pv = pv; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/BigObject.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/BigObject.java new file mode 100644 index 0000000..2f5da72 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/BigObject.java
@@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.overview; + +import lombok.Data; + +@Data +public class BigObject { + + private String label; + + private int objectId; + + private double value; + + private String description; + + public BigObject(String label, int objectId, double value, String description) { + this.label = label; + this.objectId = objectId; + this.value = value; + this.description = description; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/Details.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/Details.java new file mode 100644 index 0000000..5cec709 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/overview/Details.java
@@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.overview; + +import lombok.Data; + +@Data +public class Details { + private String jvmInfo; + private int identifierSize; + private long creationDate; + private int numberOfObjects; + private int numberOfGCRoots; + private int numberOfClasses; + private int numberOfClassLoaders; + private long usedHeapSize; + private boolean generationInfoAvailable; + + public Details(String jvmInfo, int identifierSize, long creationDate, int numberOfObjects, int numberOfGCRoots, + int numberOfClasses, int numberOfClassLoaders, long usedHeapSize, boolean generationInfoAvailable) { + this.jvmInfo = jvmInfo; + this.identifierSize = identifierSize; + this.creationDate = creationDate; + this.numberOfObjects = numberOfObjects; + this.numberOfGCRoots = numberOfGCRoots; + this.numberOfClasses = numberOfClasses; + this.numberOfClassLoaders = numberOfClassLoaders; + this.usedHeapSize = usedHeapSize; + this.generationInfoAvailable = generationInfoAvailable; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/Info.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/Info.java new file mode 100644 index 0000000..99e9493 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/Info.java
@@ -0,0 +1,47 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.thread; + +import lombok.Data; + +@Data +public class Info { + + private int objectId; + + private String object; + + private String name; + + private long shallowSize; + + private long retainedSize; + + private String contextClassLoader; + + private boolean hasStack; + + private boolean daemon; + + public Info(int objectId, String object, String name, long shallowSize, long retainedSize, + String contextClassLoader, boolean hasStack, boolean daemon) { + this.objectId = objectId; + this.object = object; + this.name = name; + this.shallowSize = shallowSize; + this.retainedSize = retainedSize; + this.contextClassLoader = contextClassLoader; + this.hasStack = hasStack; + this.daemon = daemon; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/LocalVariable.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/LocalVariable.java new file mode 100644 index 0000000..d7e455a --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/LocalVariable.java
@@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.thread; + +import org.eclipse.jifa.worker.vo.heapdump.HeapObject; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper=true) +public class LocalVariable extends HeapObject { +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/StackFrame.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/StackFrame.java new file mode 100644 index 0000000..386ee73 --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/thread/StackFrame.java
@@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.thread; + +import lombok.Data; + +@Data +public class StackFrame { + + private String stack; + + private boolean hasLocal; + + private boolean firstNonNativeFrame; + + public StackFrame(String stack, boolean hasLocal) { + this.stack = stack; + this.hasLocal = hasLocal; + } +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Record.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Record.java new file mode 100644 index 0000000..04df80d --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Record.java
@@ -0,0 +1,23 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.unreachable; + +import lombok.Data; + +@Data +public class Record { + private int objectId; + private String className; + private int objects; + private long shallowSize; +}
diff --git a/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Summary.java b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Summary.java new file mode 100644 index 0000000..31254db --- /dev/null +++ b/backend/worker/src/main/java/org/eclipse/jifa/worker/vo/heapdump/unreachable/Summary.java
@@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.vo.heapdump.unreachable; + +import lombok.Data; + +@Data +public class Summary { + + private int totalSize; + + private int objects; + + private long shallowSize; +}
diff --git a/backend/worker/src/main/resources/log4j2-prod.xml b/backend/worker/src/main/resources/log4j2-prod.xml new file mode 100644 index 0000000..9fa421c --- /dev/null +++ b/backend/worker/src/main/resources/log4j2-prod.xml
@@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<Configuration status="WARN"> + <Properties> + <Property name="baseDir">${sys:user.home}/logs/jifa</Property> + </Properties> + <Appenders> + <RollingFile name="STDOUT" append="false" + fileName="${baseDir}/stdout.log" + filePattern="${baseDir}/stdout-%d{yyyy-MM-dd}.log" + > + <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/> + <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%level] %m%n"/> + <Policies> + <TimeBasedTriggeringPolicy/> + </Policies> + </RollingFile> + + <RollingFile name="STDERR" append="false" + fileName="${baseDir}/stderr.log" + filePattern="${baseDir}/stderr-%d{yyyy-MM-dd}.log" + > + <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> + <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%level] %m%n"/> + <Policies> + <TimeBasedTriggeringPolicy/> + </Policies> + </RollingFile> + </Appenders> + + <Loggers> + <Root level="info"> + <AppenderRef ref="STDOUT"/> + <AppenderRef ref="STDERR"/> + </Root> + + <Logger name="org.eclipse.jifa" level="info" additivity="false"> + <AppenderRef ref="STDOUT"/> + <AppenderRef ref="STDERR"/> + </Logger> + </Loggers> +</Configuration> \ No newline at end of file
diff --git a/backend/worker/src/main/resources/log4j2-test.xml b/backend/worker/src/main/resources/log4j2-test.xml new file mode 100644 index 0000000..b949fe7 --- /dev/null +++ b/backend/worker/src/main/resources/log4j2-test.xml
@@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<Configuration status="WARN"> + <Appenders> + <Console name="STDOUT" target="SYSTEM_OUT"> + <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%level] %m%n"/> + </Console> + </Appenders> + + <Loggers> + <Logger name="org.eclipse.jifa" level="debug" additivity="false"> + <AppenderRef ref="STDOUT"/> + </Logger> + + <Root level="info"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> +</Configuration> \ No newline at end of file
diff --git a/backend/worker/src/main/resources/vertx-config.json b/backend/worker/src/main/resources/vertx-config.json new file mode 100644 index 0000000..b447e89 --- /dev/null +++ b/backend/worker/src/main/resources/vertx-config.json
@@ -0,0 +1,5 @@ +{ + "workerPoolSize": 32, + "maxWorkerExecuteTime": 15, + "maxWorkerExecuteTimeUnit": "MINUTES" +} \ No newline at end of file
diff --git a/backend/worker/src/main/resources/worker-config.json b/backend/worker/src/main/resources/worker-config.json new file mode 100644 index 0000000..b1cd180 --- /dev/null +++ b/backend/worker/src/main/resources/worker-config.json
@@ -0,0 +1,4 @@ +{ + "server.port": 8102, + "api.prefix": "/jifa-api" +} \ No newline at end of file
diff --git a/backend/worker/src/test/java/org/eclipse/jifa/worker/route/Base.java b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/Base.java new file mode 100644 index 0000000..c13af6a --- /dev/null +++ b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/Base.java
@@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import org.eclipse.jifa.worker.Constant; +import org.eclipse.jifa.worker.Global; + +public class Base { + + static WebClient CLIENT = WebClient.create(Vertx.vertx()); + + static String TEST_HEAP_DUMP_FILENAME; + + public static String uri(String uri) { + return Global.stringConfig(Constant.ConfigKey.API_PREFIX) + uri; + } + +}
diff --git a/backend/worker/src/test/java/org/eclipse/jifa/worker/route/FileRouteSuite.java b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/FileRouteSuite.java new file mode 100644 index 0000000..1f28e08 --- /dev/null +++ b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/FileRouteSuite.java
@@ -0,0 +1,44 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import com.google.gson.reflect.TypeToken; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.vo.FileInfo; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.worker.Global; + +import java.lang.reflect.Type; + +import static org.eclipse.jifa.common.util.GsonHolder.GSON; + +public class FileRouteSuite extends Base { + + public static void test(TestContext context) { + Async async = context.async(); + CLIENT.get(Global.PORT, Global.HOST, uri("/files")) + .addQueryParam("type", FileType.HEAP_DUMP.name()) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .send(ar -> { + context.assertTrue(ar.succeeded()); + Type type = new TypeToken<PageView<FileInfo>>() { + }.getType(); + PageView<FileInfo> view = GSON.fromJson(ar.result().bodyAsString(), type); + context.assertTrue(view.getData().size() > 0); + async.complete(); + }); + } +}
diff --git a/backend/worker/src/test/java/org/eclipse/jifa/worker/route/HeapDumpRouteSuite.java b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/HeapDumpRouteSuite.java new file mode 100644 index 0000000..64a79dc --- /dev/null +++ b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/HeapDumpRouteSuite.java
@@ -0,0 +1,272 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import com.google.gson.reflect.TypeToken; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.web.client.HttpRequest; +import io.vertx.ext.web.client.HttpResponse; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.common.vo.PageView; +import org.eclipse.jifa.common.vo.Progress; +import org.eclipse.jifa.common.vo.Result; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.worker.vo.heapdump.classloader.Record; +import org.eclipse.jifa.worker.vo.heapdump.inspector.ObjectView; +import org.eclipse.jifa.worker.vo.heapdump.thread.Info; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.eclipse.jifa.common.Constant.HTTP_GET_OK_STATUS_CODE; +import static org.eclipse.jifa.common.Constant.HTTP_POST_CREATED_STATUS_CODE; +import static org.eclipse.jifa.common.util.GsonHolder.GSON; + +public class HeapDumpRouteSuite extends Base { + + static TestContext context; + private static Logger LOGGER = LoggerFactory.getLogger(HeapDumpRouteSuite.class); + + public static void test(TestContext c) throws Exception { + context = c; + Holder holder = new Holder(); + + testGet("/isFirstAnalysis", + (PostProcessor) resp -> { + Type type = new TypeToken<Result<Boolean>>() { + }.getType(); + Result<Boolean> result = GSON.fromJson(resp.bodyAsString(), type); + context.assertTrue(result.getResult()); + + }); + + testPost("/analyze"); + + AtomicBoolean success = new AtomicBoolean(); + while (!success.get()) { + testGet("/progressOfAnalysis", + (PostProcessor) resp -> { + Progress progress = GSON.fromJson(resp.bodyAsString(), Progress.class); + ProgressState state = progress.getState(); + context.assertTrue(state == ProgressState.IN_PROGRESS || state == ProgressState.SUCCESS); + if (state == ProgressState.SUCCESS) { + success.set(true); + } + }); + Thread.sleep(200); + } + + // overview + testGet("/details"); + testGet("/biggestObjects"); + + // class loader + testGet("/classLoaderExplorer/summary"); + testGet("/classLoaderExplorer/classLoader", + req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10"), + resp -> { + Type type = new TypeToken<PageView<Record>>() { + }.getType(); + PageView<Record> result = GSON.fromJson(resp.bodyAsString(), type); + holder.id = result.getData().get(0).getObjectId(); + }); + testGet("/classLoaderExplorer/children", + (PreProcessor) req -> req.addQueryParam("classLoaderId", String.valueOf(holder.id)) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + + // class reference + testGet("/classReference/inbounds/class", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id))); + testGet("/classReference/outbounds/class", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id))); + + // direct byte buffer + testGet("/directByteBuffer/summary"); + testGet("/directByteBuffer/records", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + + // dominator tree + testGet("/dominatorTree/roots", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .addQueryParam("grouping", "NONE")); + testGet("/dominatorTree/children", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .addQueryParam("grouping", "NONE") + .addQueryParam("parentObjectId", String.valueOf(holder.id))); + + // gc root + testGet("/GCRoots"); + testGet("/GCRoots/classes", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .addQueryParam("rootTypeIndex", "1")); + testGet("/GCRoots/class/objects", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .addQueryParam("rootTypeIndex", "1") + .addQueryParam("classIndex", "1")); + + // histogram + testGet("/histogram", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10") + .addQueryParam("groupingBy", "BY_CLASS")); + + // inspector + testGet("/inspector/objectView", + req -> req.addQueryParam("objectId", String.valueOf(holder.id)), + resp -> { + ObjectView objectView = GSON.fromJson(resp.bodyAsString(), ObjectView.class); + holder.objectAddress = objectView.getObjectAddress(); + }); + testGet("/inspector/addressToId", + (PreProcessor) req -> req.addQueryParam("objectAddress", String.valueOf(holder.objectAddress))); + testGet("/inspector/value", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id))); + testGet("/inspector/fields", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id)) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + testGet("/inspector/staticFields", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id)) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + + // leak report + testGet("/leak/report"); + + // object list + testGet("/outbounds", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id)) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + testGet("/inbounds", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id)) + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + + // object + testGet("/object", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id))); + + // oql + testGet("/oql", + (PreProcessor) req -> req.addQueryParam("oql", "select * from java.lang.String") + .addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + + // path to gc roots + testGet("/pathToGCRoots", + (PreProcessor) req -> req.addQueryParam("origin", String.valueOf(holder.id)) + .addQueryParam("skip", "0") + .addQueryParam("count", "10")); + + // system property + testGet("/systemProperties"); + + // thread + testGet("/threadsSummary"); + testGet("/threads", + req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10"), + resp -> { + Type type = new TypeToken<PageView<Info>>() { + }.getType(); + PageView<Info> result = GSON.fromJson(resp.bodyAsString(), type); + holder.id = result.getData().get(0).getObjectId(); + } + ); + testGet("/stackTrace", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id))); + testGet("/locals", + (PreProcessor) req -> req.addQueryParam("objectId", String.valueOf(holder.id)) + .addQueryParam("depth", "1") + .addQueryParam("firstNonNativeFrame", "false")); + + + // unreachable objects + testGet("/unreachableObjects/summary"); + testGet("/unreachableObjects/records", + (PreProcessor) req -> req.addQueryParam("page", "1") + .addQueryParam("pageSize", "10")); + } + + static void testGet(String uri) { + testGet(uri, null, null); + } + + static void testGet(String uri, PreProcessor processor) { + testGet(uri, processor, null); + } + + static void testGet(String uri, PostProcessor postProcessor) { + testGet(uri, null, postProcessor); + } + + static void testGet(String uri, PreProcessor processor, PostProcessor postProcessor) { + test(uri, HttpMethod.GET, processor, postProcessor); + } + + static void testPost(String uri) { + test(uri, HttpMethod.POST, null, null); + } + + static void test(String uri, HttpMethod method, PreProcessor processor, PostProcessor postProcessor) { + LOGGER.info("test {}", uri); + Async async = context.async(); + HttpRequest<Buffer> request = + CLIENT.request(method, Global.PORT, Global.HOST, uri("/heap-dump/" + TEST_HEAP_DUMP_FILENAME + uri)); + if (processor != null) { + processor.process(request); + } + request.send( + ar -> { + context.assertTrue(ar.succeeded()); + context.assertEquals(ar.result().statusCode(), + method == HttpMethod.GET ? HTTP_GET_OK_STATUS_CODE : HTTP_POST_CREATED_STATUS_CODE, + ar.result().bodyAsString()); + + if (postProcessor != null) { + postProcessor.process(ar.result()); + } + LOGGER.info("{}: {}", uri, ar.result().bodyAsString()); + async.complete(); + } + ); + async.awaitSuccess(); + } + + interface PreProcessor { + void process(HttpRequest<Buffer> request); + } + + interface PostProcessor { + void process(HttpResponse<Buffer> resp); + } + + static class Holder { + int id; + + long objectAddress; + } +}
diff --git a/backend/worker/src/test/java/org/eclipse/jifa/worker/route/TestRoutes.java b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/TestRoutes.java new file mode 100644 index 0000000..341a7bc --- /dev/null +++ b/backend/worker/src/test/java/org/eclipse/jifa/worker/route/TestRoutes.java
@@ -0,0 +1,71 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.jifa.worker.route; + +import com.google.common.io.Files; +import com.sun.management.HotSpotDiagnosticMXBean; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.apache.commons.io.FileUtils; +import org.eclipse.jifa.common.enums.FileType; +import org.eclipse.jifa.common.enums.ProgressState; +import org.eclipse.jifa.worker.Global; +import org.eclipse.jifa.worker.Starter; +import org.eclipse.jifa.worker.support.FileSupport; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.management.ManagementFactory; + +@RunWith(VertxUnitRunner.class) +public class TestRoutes { + + private static Logger LOGGER = LoggerFactory.getLogger(TestRoutes.class); + + @Before + public void setup(TestContext context) throws Exception { + // start worker + Starter.main(new String[]{}); + + // prepare heap dump file + HotSpotDiagnosticMXBean mxBean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + String name = "test_dump_" + System.currentTimeMillis() + ".hprof"; + Base.TEST_HEAP_DUMP_FILENAME = name; + mxBean.dumpHeap(name, false); + FileSupport.initInfoFile(FileType.HEAP_DUMP, name, name); + Files.move(new File(name), new File(FileSupport.filePath(FileType.HEAP_DUMP, name))); + FileSupport.updateTransferState(FileType.HEAP_DUMP, name, ProgressState.SUCCESS); + } + + @Test + public void testRoutes(TestContext context) throws Exception { + FileRouteSuite.test(context); + HeapDumpRouteSuite.test(context); + } + + @After + public void tearDown(TestContext context) { + try { + System.out.println(context); + FileUtils.deleteDirectory(new File(Global.workspace())); + Global.VERTX.close(context.asyncAssertSuccess()); + } catch (Throwable t) { + LOGGER.error("Error", t); + } + } +}
diff --git a/backend/worker/src/test/resources/vertx-config.json b/backend/worker/src/test/resources/vertx-config.json new file mode 100644 index 0000000..b447e89 --- /dev/null +++ b/backend/worker/src/test/resources/vertx-config.json
@@ -0,0 +1,5 @@ +{ + "workerPoolSize": 32, + "maxWorkerExecuteTime": 15, + "maxWorkerExecuteTimeUnit": "MINUTES" +} \ No newline at end of file
diff --git a/backend/worker/src/test/resources/worker-config.json b/backend/worker/src/test/resources/worker-config.json new file mode 100644 index 0000000..340111c --- /dev/null +++ b/backend/worker/src/test/resources/worker-config.json
@@ -0,0 +1,5 @@ +{ + "server.host": "localhost", + "api.prefix": "/jifa-api", + "workspace": ".test_jifa_workspace" +} \ No newline at end of file
diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..09e8d65 --- /dev/null +++ b/build.gradle
@@ -0,0 +1,16 @@ +allprojects { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + jcenter() + mavenCentral() + } +} + +subprojects { + apply plugin: 'idea' + version = '0.1' +} + +defaultTasks 'build'
diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..3b2cd3c --- /dev/null +++ b/frontend/README.md
@@ -0,0 +1,29 @@ +# jifa + +## Project setup +``` +npm install +``` + +### Compiles and hot-reloads for development +``` +npm run serve +``` + +### Compiles and minifies for production +``` +npm run build +``` + +### Run your tests +``` +npm run test +``` + +### Lints and fixes files +``` +npm run lint +``` + +### Customize configuration +See [Configuration Reference](https://cli.vuejs.org/config/).
diff --git a/frontend/babel.config.js b/frontend/babel.config.js new file mode 100644 index 0000000..6f25b24 --- /dev/null +++ b/frontend/babel.config.js
@@ -0,0 +1,17 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +module.exports = { + presets: [ + '@vue/app' + ] +}
diff --git a/frontend/build.gradle b/frontend/build.gradle new file mode 100644 index 0000000..d3016d1 --- /dev/null +++ b/frontend/build.gradle
@@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + + dependencies { + classpath "com.moowork.gradle:gradle-node-plugin:1.3.1" + } +} + +apply plugin: 'base' +apply plugin: 'com.moowork.node' + +node { + version = '10.14.1' + npmVersion = '6.4.1' + download = true +} + +npm_run_build { + inputs.files fileTree("public") + inputs.files fileTree("src") + inputs.file 'package.json' + inputs.file 'package-lock.json' + outputs.dir 'build' +} + +task copy_build(type: Copy) { + dependsOn npm_run_build + from "build" as Object + into "${project.rootDir}/build/static" as Object +} + +assemble.dependsOn copy_build
diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..6381534 --- /dev/null +++ b/frontend/package-lock.json
@@ -0,0 +1,12854 @@ +{ + "name": "Jifa", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.0.0.tgz", + "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/core/download/@babel/core-7.4.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcore%2Fdownload%2F%40babel%2Fcore-7.4.0.tgz", + "integrity": "sha1-JI/Wh0t9dVAQv+YfVXRh1PRG2ek=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helpers": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.4.0.tgz", + "integrity": "sha1-wjDnlYmuenKf1GMbne1NwiBBgZY=", + "dev": true, + "requires": { + "@babel/types": "^7.4.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha1-Mj053QtQ4Qx8Bsp9djjmhk2MXDI=", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-builder-binary-assignment-operator-visitor/download/@babel/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha1-a2lijf5Ah3mODE7Zjj1Kay+9L18=", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-call-delegate/download/@babel/helper-call-delegate-7.4.0.tgz", + "integrity": "sha1-8wjqvg1E9FEheFOu303qX2/jKU8=", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.4.0.tgz", + "integrity": "sha1-MP0JDgWdAhmVwXYqW3Z5j6C1HYI=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.0", + "@babel/helper-split-export-declaration": "^7.4.0" + } + }, + "@babel/helper-define-map": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-define-map/download/@babel/helper-define-map-7.4.0.tgz", + "integrity": "sha1-y/2MGy8ScI4mLCb2AM0W7Wo7xsk=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.4.0", + "lodash": "^4.17.11" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha1-U3+hP28WdN90WwwA7I/k6ZaByPY=", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.1.0.tgz", + "integrity": "sha1-oM6wFoX3M1XUNgwSR/WCv6/I/1M=", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha1-g1ctQyDipGVyY3NBE8QoaLZOScM=", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.4.0.tgz", + "integrity": "sha1-JbYhOZriKYaTKXMKYgFbvrCm+9Y=", + "dev": true, + "requires": { + "@babel/types": "^7.4.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha1-jNFLCg33/wDwCefXpDaUX0fHoW8=", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.0.0.tgz", + "integrity": "sha1-lggbcRHkhtpNLNlxrRpP4hbMLj0=", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.2.2", + "resolved": "http://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.2.2.tgz", + "integrity": "sha1-qy+OjSMUCfg3DIg9IMM1GQKEuWM=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.2.2", + "@babel/types": "^7.2.2", + "lodash": "^4.17.10" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha1-opIMVwKwc8Fd5REGIAqoytIEl9U=", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha1-u7P77phmHFaQNCN8wDlnupm08lA=", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-regex/download/@babel/helper-regex-7.0.0.tgz", + "integrity": "sha1-LBcYkjtX+bvmRwX/5WQKxk2b2yc=", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha1-Nh2AghtvONp1vT8HheziCojF/n8=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.4.0.tgz", + "integrity": "sha1-T1attq7c1EnS2pOZwtzwVFRjtkw=", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.1.0.tgz", + "integrity": "sha1-Ze65VMjCRb6qToWdphiPOdceWFw=", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha1-Vxv9UnAfSSkg1jt/c1Aw6aPhC1U=", + "dev": true, + "requires": { + "@babel/types": "^7.4.0" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.2.0.tgz", + "integrity": "sha1-xOABJEV2nigVtVKW6tQ6lYVJ9vo=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/helpers/download/@babel/helpers-7.4.2.tgz", + "integrity": "sha1-O9+kalUsp371oPhVG+XwhFrpib4=", + "dev": true, + "requires": { + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.0.0.tgz", + "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.4.2.tgz", + "integrity": "sha1-tFIaQAy1qHHqs4kHh7S8EybTjZE=", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-async-generator-functions/download/@babel/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha1-somzBmadzkrSCwJSiJoVdoydQX4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-class-properties/download/@babel/plugin-proposal-class-properties-7.4.0.tgz", + "integrity": "sha1-1w22Gi8f153pJ+6pH2QRyWTghLg=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-decorators/download/@babel/plugin-proposal-decorators-7.4.0.tgz", + "integrity": "sha1-jhv9g++lSl9mIDOvzCuOcB9Ls6k=", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-decorators": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-json-strings/download/@babel/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha1-Vo7MRGxhSK5rJn8CVREwiR4p8xc=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-object-rest-spread/download/@babel/plugin-proposal-object-rest-spread-7.4.0.tgz", + "integrity": "sha1-5JYFdSBerfKhq04MeflQTVuCqX8=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-optional-catch-binding/download/@babel/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha1-E12B7baKCB5V5W7EhUHs6AZcOPU=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-proposal-unicode-property-regex/download/@babel/plugin-proposal-unicode-property-regex-7.4.0.tgz", + "integrity": "sha1-IC2R7pd9dg74P09BaygNVovoRiM=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-async-generators/download/@babel/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha1-aeHw2zTG9aDPfiszI78VmnbIy38=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-decorators/download/@babel/plugin-syntax-decorators-7.2.0.tgz", + "integrity": "sha1-xQsblX3MaeSxEntl4cM+72FXDBs=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-dynamic-import/download/@babel/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha1-acFZ/69JmBIhYa2OvF5tH1XfhhI=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-json-strings/download/@babel/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha1-cr0T9v/h0lk4Ep0qGGsR/WKVFHA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.2.0.tgz", + "integrity": "sha1-C4WjtLx830zEuL8jYzW5B8oi58c=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-object-rest-spread/download/@babel/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha1-O3o+czUQxX6CC5FCpleayLDfrS4=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-syntax-optional-catch-binding/download/@babel/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha1-qUAT1u2okI3+akd+f57ahWVuz1w=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-arrow-functions/download/@babel/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha1-mur75Nb/xlY7+Pg3IJFijwB3lVA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-async-to-generator/download/@babel/plugin-transform-async-to-generator-7.4.0.tgz", + "integrity": "sha1-I0/j5Fjc6VhlwNFS0lYRmyN4NLA=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-block-scoped-functions/download/@babel/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha1-XTzBHo1d3XUqpkyRSNDbbLef0ZA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-block-scoping/download/@babel/plugin-transform-block-scoping-7.4.0.tgz", + "integrity": "sha1-Fk3zu0Hj3rlUxMoy/6n8qlbTC8s=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-classes/download/@babel/plugin-transform-classes-7.4.0.tgz", + "integrity": "sha1-40KNPIo9AfM7EMUpuZi6FwcEPU0=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-computed-properties/download/@babel/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha1-g6ffamWIZbHI9kHVEMbzryICFto=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-destructuring/download/@babel/plugin-transform-destructuring-7.4.0.tgz", + "integrity": "sha1-rLubJBjSkBB9szP01s2Kpq6gA0M=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-dotall-regex/download/@babel/plugin-transform-dotall-regex-7.2.0.tgz", + "integrity": "sha1-8Kq7k9EgqKxh6SXqC6RAgS2+Dkk=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-duplicate-keys/download/@babel/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha1-2VLEkw8xKk2//xjwspFOYMNVMLM=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-exponentiation-operator/download/@babel/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha1-pjhoKJ5bQAf3BU1GSRr1FDV2YAg=", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-for-of/download/@babel/plugin-transform-for-of-7.4.0.tgz", + "integrity": "sha1-VsjDZnf11KFrgLEve3aN4GSq618=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-function-name/download/@babel/plugin-transform-function-name-7.2.0.tgz", + "integrity": "sha1-95MDYoKf+ZoxdMOfCvzAJO9Zcxo=", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-literals/download/@babel/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha1-aQNT6B+SZ9rU/Yz9d+r6hqulPqE=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-modules-amd/download/@babel/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha1-gqm85FuVRB9heiQBHcidEtp/TuY=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-modules-commonjs/download/@babel/plugin-transform-modules-commonjs-7.4.0.tgz", + "integrity": "sha1-O47GFxTTt10gxcz6FX8sLgh/1Mo=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-modules-systemjs/download/@babel/plugin-transform-modules-systemjs-7.4.0.tgz", + "integrity": "sha1-wkleVVKBNXl7yBb11Q+FFpjFhqE=", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-modules-umd/download/@babel/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha1-dnjOdRafCHe46yI1U4wHQmjdAa4=", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-named-capturing-groups-regex/download/@babel/plugin-transform-named-capturing-groups-regex-7.4.2.tgz", + "integrity": "sha1-gAORE21svMgHKNvbo8HG5G+GwS4=", + "dev": true, + "requires": { + "regexp-tree": "^0.1.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-new-target/download/@babel/plugin-transform-new-target-7.4.0.tgz", + "integrity": "sha1-Z2WKHZRO21PI1PowBEc6DdeDgVA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-object-super/download/@babel/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha1-s11MEPVrq11lAEfa0PHY6IFLZZg=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-parameters/download/@babel/plugin-transform-parameters-7.4.0.tgz", + "integrity": "sha1-oTCUJvrE7s0qlDmkyMNRJKEaSKk=", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-regenerator/download/@babel/plugin-transform-regenerator-7.4.0.tgz", + "integrity": "sha1-B4DifuRYzD/brRgpTXA+lyrh9tE=", + "dev": true, + "requires": { + "regenerator-transform": "^0.13.4" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-runtime/download/@babel/plugin-transform-runtime-7.4.0.tgz", + "integrity": "sha1-tNjJJe2VdHG8V+C52lNAjrse1Fc=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha1-YzOu4vjW7n4oYVRXKYk0o7RhmPA=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-spread/download/@babel/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha1-MQOpq+IvdCttQG7NPNSbd0kZtAY=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-sticky-regex/download/@babel/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha1-oeRUtZlVYKnB4NU338FQYf0mh+E=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-template-literals/download/@babel/plugin-transform-template-literals-7.2.0.tgz", + "integrity": "sha1-2H7QG46qx6kkc/YIyXwIneK6Hls=", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-typeof-symbol/download/@babel/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha1-EX0rzsL79ktLWdH5gZiUaC0p8rI=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.2.0", + "resolved": "http://registry.npm.taobao.org/@babel/plugin-transform-unicode-regex/download/@babel/plugin-transform-unicode-regex-7.2.0.tgz", + "integrity": "sha1-TrjbFvly+Ku1BiwWG4sRVUat4Is=", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/preset-env": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/preset-env/download/@babel/preset-env-7.4.2.tgz", + "integrity": "sha1-L1uh3i2u+p3MplOEj5bHzi5AZnY=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.0", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.0", + "@babel/plugin-transform-classes": "^7.4.0", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.0", + "@babel/plugin-transform-dotall-regex": "^7.2.0", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.0", + "@babel/plugin-transform-function-name": "^7.2.0", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.0", + "@babel/plugin-transform-modules-systemjs": "^7.4.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.2", + "@babel/plugin-transform-new-target": "^7.4.0", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.0", + "@babel/plugin-transform-regenerator": "^7.4.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.2.0", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.2.0", + "@babel/types": "^7.4.0", + "browserslist": "^4.4.2", + "core-js-compat": "^3.0.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" + } + }, + "@babel/runtime": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.4.2.tgz", + "integrity": "sha1-9atolzIPFt7NhV7tcLcFkIoxP+g=", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/runtime-corejs2": { + "version": "7.4.2", + "resolved": "http://registry.npm.taobao.org/@babel/runtime-corejs2/download/@babel/runtime-corejs2-7.4.2.tgz", + "integrity": "sha1-oM7CxBcX+kFenCBPMrYD2IsXlsI=", + "dev": true, + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/template": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/template/download/@babel/template-7.4.0.tgz", + "integrity": "sha1-EkdOnAd7rlhcXYNalcCwt5DCXIs=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/traverse": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.4.0.tgz", + "integrity": "sha1-FABpZ90dKzSUzdZQxobbna8N2to=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.0", + "resolved": "http://registry.npm.taobao.org/@babel/types/download/@babel/types-7.4.0.tgz", + "integrity": "sha1-Zwck930kzObMfYz2RZnVEdFkiUw=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "@fortawesome/fontawesome-free": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.12.1.tgz", + "integrity": "sha512-ZtjIIFplxncqxvogq148C3hBLQE+W3iJ8E4UvJ09zIJUgzwLcROsWwFDErVSXY2Plzao5J9KUYNHKHMEUYDMKw==" + }, + "@intervolga/optimize-cssnano-plugin": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@intervolga/optimize-cssnano-plugin/-/optimize-cssnano-plugin-1.0.6.tgz", + "integrity": "sha512-zN69TnSr0viRSU6cEDIcuPcP67QcpQ6uHACg58FiN9PDrU6SLyGW3MR4tiISbYxy1kDWAVPwD+XwQTWE5cigAA==", + "dev": true, + "requires": { + "cssnano": "^4.0.0", + "cssnano-preset-default": "^4.0.0", + "postcss": "^7.0.0" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "http://registry.npm.taobao.org/@mrmlnc/readdir-enhanced/download/@mrmlnc/readdir-enhanced-2.2.1.tgz", + "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-1.1.3.tgz", + "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", + "dev": true + }, + "@nuxt/opencollective": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.2.2.tgz", + "integrity": "sha512-ie50SpS47L+0gLsW4yP23zI/PtjsDRglyozX2G09jeiUazC1AJlGPZo0JUs9iuCDUoIgsDEf66y7/bSfig0BpA==", + "requires": { + "chalk": "^2.4.1", + "consola": "^2.3.0", + "node-fetch": "^2.3.0" + } + }, + "@soda/friendly-errors-webpack-plugin": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.1.tgz", + "integrity": "sha512-cWKrGaFX+rfbMrAxVv56DzhPNqOJPZuNIS2HGMELtgGzb+vsMzyig9mml5gZ/hr2BGtSLV+dP2LUEuAL8aG2mQ==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "error-stack-parser": "^2.0.0", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "@types/events": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/@types/events/download/@types/events-3.0.0.tgz", + "integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "http://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.1.tgz", + "integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "http://registry.npm.taobao.org/@types/minimatch/download/@types/minimatch-3.0.3.tgz", + "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", + "dev": true + }, + "@types/node": { + "version": "11.11.5", + "resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-11.11.5.tgz", + "integrity": "sha1-DFfhLrRNROW2c1WTklKGVT7nzr8=", + "dev": true + }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.0.0-beta.3.tgz", + "integrity": "sha1-5MLnEls+DSqdST5FeFCyq7D9PK0=", + "dev": true + }, + "@vue/babel-plugin-transform-vue-jsx": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-plugin-transform-vue-jsx/download/@vue/babel-plugin-transform-vue-jsx-1.0.0-beta.3.tgz", + "integrity": "sha1-oaROgB2O1hXknxRe8bPqyiwW4uY=", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.3", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-preset-app": { + "version": "3.5.1", + "resolved": "http://registry.npm.taobao.org/@vue/babel-preset-app/download/@vue/babel-preset-app-3.5.1.tgz", + "integrity": "sha1-Ez/oMsy5pVe6lG+mYDXb5bnGHlk=", + "dev": true, + "requires": { + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-decorators": "^7.1.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/preset-env": "^7.0.0", + "@babel/runtime": "^7.0.0", + "@babel/runtime-corejs2": "^7.2.0", + "@vue/babel-preset-jsx": "^1.0.0-beta.2", + "babel-plugin-dynamic-import-node": "^2.2.0", + "core-js": "^2.6.5" + } + }, + "@vue/babel-preset-jsx": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-preset-jsx/download/@vue/babel-preset-jsx-1.0.0-beta.3.tgz", + "integrity": "sha1-FcWEvWLAKGqA8BlnSa44zeXNcDs=", + "dev": true, + "requires": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.3", + "@vue/babel-plugin-transform-vue-jsx": "^1.0.0-beta.3", + "@vue/babel-sugar-functional-vue": "^1.0.0-beta.3", + "@vue/babel-sugar-inject-h": "^1.0.0-beta.3", + "@vue/babel-sugar-v-model": "^1.0.0-beta.3", + "@vue/babel-sugar-v-on": "^1.0.0-beta.3" + } + }, + "@vue/babel-sugar-functional-vue": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-sugar-functional-vue/download/@vue/babel-sugar-functional-vue-1.0.0-beta.3.tgz", + "integrity": "sha1-QahVeGlx2su+gESFju/pjeCJvxI=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-inject-h": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-sugar-inject-h/download/@vue/babel-sugar-inject-h-1.0.0-beta.3.tgz", + "integrity": "sha1-vh0At0oaif7TWpsUFac4w28SWWY=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-v-model": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-sugar-v-model/download/@vue/babel-sugar-v-model-1.0.0-beta.3.tgz", + "integrity": "sha1-6pNbDgi/WMEloTSbgZFWBZWQmTw=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.3", + "@vue/babel-plugin-transform-vue-jsx": "^1.0.0-beta.3", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-sugar-v-on": { + "version": "1.0.0-beta.3", + "resolved": "http://registry.npm.taobao.org/@vue/babel-sugar-v-on/download/@vue/babel-sugar-v-on-1.0.0-beta.3.tgz", + "integrity": "sha1-L1/ttDiD9gP+dgEPJTuFx0ZYVf4=", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.0.0-beta.3", + "camelcase": "^5.0.0" + } + }, + "@vue/cli-overlay": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-3.6.0.tgz", + "integrity": "sha512-U9zcnnISJCA+dp7lLr1gTYfVqGfQ+y0jJ8LCZsZPxHpHr1QQDfMv9zqGOXQlv2+UVshvLi8ZWvD5AZSfHZ5h7w==", + "dev": true + }, + "@vue/cli-plugin-babel": { + "version": "3.5.1", + "resolved": "http://registry.npm.taobao.org/@vue/cli-plugin-babel/download/@vue/cli-plugin-babel-3.5.1.tgz", + "integrity": "sha1-q4cp/1O7UIYTuZjN0uJaeN79MMg=", + "dev": true, + "requires": { + "@babel/core": "^7.0.0", + "@vue/babel-preset-app": "^3.5.1", + "@vue/cli-shared-utils": "^3.5.1", + "babel-loader": "^8.0.5", + "webpack": ">=4 < 4.29" + } + }, + "@vue/cli-plugin-eslint": { + "version": "3.5.1", + "resolved": "http://registry.npm.taobao.org/@vue/cli-plugin-eslint/download/@vue/cli-plugin-eslint-3.5.1.tgz", + "integrity": "sha1-ILRom+NdayFGy94utvnS8wM6DoE=", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^3.5.1", + "babel-eslint": "^10.0.1", + "eslint": "^4.19.1", + "eslint-loader": "^2.1.2", + "eslint-plugin-vue": "^4.7.1", + "globby": "^9.0.0", + "webpack": ">=4 < 4.29" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "http://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "optional": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "http://registry.npm.taobao.org/eslint/download/eslint-4.19.1.tgz", + "integrity": "sha1-MtHWU+HZBAiFS/spbwdux+GGowA=", + "dev": true, + "optional": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "eslint-plugin-vue": { + "version": "4.7.1", + "resolved": "http://registry.npm.taobao.org/eslint-plugin-vue/download/eslint-plugin-vue-4.7.1.tgz", + "integrity": "sha1-yCm5/GJYLBiXtaC5Sv1E7MpRHmM=", + "dev": true, + "optional": true, + "requires": { + "vue-eslint-parser": "^2.0.3" + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-3.7.3.tgz", + "integrity": "sha1-u1ByANPRf2AkdjYWC0gmKEsQhTU=", + "dev": true, + "optional": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "optional": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "optional": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "dev": true, + "optional": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true, + "optional": true + } + } + }, + "@vue/cli-service": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-3.6.0.tgz", + "integrity": "sha512-MJeSjIf/IposSjJ93kRs5R8pfxqO7j2eXcIes2bwt3J9Ql8aoO5XAUi7IZphaxZHANIIbYJno+OUVtf90yMaqg==", + "dev": true, + "requires": { + "@intervolga/optimize-cssnano-plugin": "^1.0.5", + "@soda/friendly-errors-webpack-plugin": "^1.7.1", + "@vue/cli-overlay": "^3.6.0", + "@vue/cli-shared-utils": "^3.6.0", + "@vue/component-compiler-utils": "^2.6.0", + "@vue/preload-webpack-plugin": "^1.1.0", + "@vue/web-component-wrapper": "^1.2.0", + "acorn": "^6.1.1", + "acorn-walk": "^6.1.1", + "address": "^1.0.3", + "autoprefixer": "^9.5.1", + "browserslist": "^4.5.4", + "cache-loader": "^2.0.1", + "case-sensitive-paths-webpack-plugin": "^2.2.0", + "chalk": "^2.4.2", + "clipboardy": "^2.0.0", + "cliui": "^5.0.0", + "copy-webpack-plugin": "^4.6.0", + "css-loader": "^1.0.1", + "cssnano": "^4.1.10", + "current-script-polyfill": "^1.0.0", + "debug": "^4.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "escape-string-regexp": "^1.0.5", + "file-loader": "^3.0.1", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "hash-sum": "^1.0.2", + "html-webpack-plugin": "^3.2.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.0", + "lodash.mapvalues": "^4.6.0", + "lodash.transform": "^4.6.0", + "mini-css-extract-plugin": "^0.6.0", + "minimist": "^1.2.0", + "ora": "^3.4.0", + "portfinder": "^1.0.20", + "postcss-loader": "^3.0.0", + "read-pkg": "^5.0.0", + "semver": "^6.0.0", + "slash": "^2.0.0", + "source-map-url": "^0.4.0", + "ssri": "^6.0.1", + "string.prototype.padend": "^3.0.0", + "terser-webpack-plugin": "^1.2.3", + "thread-loader": "^2.1.2", + "url-loader": "^1.1.2", + "vue-loader": "^15.7.0", + "webpack": ">=4 < 4.29", + "webpack-bundle-analyzer": "^3.3.0", + "webpack-chain": "^4.11.0", + "webpack-dev-server": "^3.3.1", + "webpack-merge": "^4.2.1", + "yorkie": "^2.0.0" + }, + "dependencies": { + "@vue/cli-shared-utils": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-3.6.0.tgz", + "integrity": "sha512-C8nTiJ7o+dncNLyOIOZF8P4bMJdOVXhWOuwyZKqn8k3CcsQVzuLyCKUHHezWc+sI+PJi4wIg2ZffCiueeIXZ+w==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "execa": "^1.0.0", + "joi": "^14.3.0", + "launch-editor": "^2.2.1", + "lru-cache": "^5.1.1", + "node-ipc": "^9.1.1", + "opn": "^5.3.0", + "ora": "^3.4.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.7", + "semver": "^6.0.0", + "string.prototype.padstart": "^3.0.0" + } + }, + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "browserslist": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.5.tgz", + "integrity": "sha512-0QFO1r/2c792Ohkit5XI8Cm8pDtZxgNl2H6HU4mHrpYz7314pEYcsAVVatM0l/YmxPnEzh9VygXouj4gkFUTKA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000960", + "electron-to-chromium": "^1.3.124", + "node-releases": "^1.1.14" + } + }, + "caniuse-lite": { + "version": "1.0.30000962", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000962.tgz", + "integrity": "sha512-WXYsW38HK+6eaj5IZR16Rn91TGhU3OhbwjKZvJ4HN/XBIABLKfbij9Mnd3pM0VEwZSlltWjoWg3I8FQ0DGgNOA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.124", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz", + "integrity": "sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w==", + "dev": true + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "node-releases": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.15.tgz", + "integrity": "sha512-cKV097BQaZr8LTSRUa2+oc/aX5L8UkZtPQrMSTgiJEeaW7ymTDCoRaGCoaTqk0lqnalcoSHu4wjSl0Cmj2+bMw==", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } + } + }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + } + }, + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true + } + } + }, + "@vue/cli-shared-utils": { + "version": "3.5.1", + "resolved": "http://registry.npm.taobao.org/@vue/cli-shared-utils/download/@vue/cli-shared-utils-3.5.1.tgz", + "integrity": "sha1-cdZvBvxhm6KN8nm9fTe6G6KckGY=", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "execa": "^1.0.0", + "joi": "^14.3.0", + "launch-editor": "^2.2.1", + "lru-cache": "^5.1.1", + "node-ipc": "^9.1.1", + "opn": "^5.3.0", + "ora": "^3.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.7", + "semver": "^5.5.0", + "string.prototype.padstart": "^3.0.0" + } + }, + "@vue/component-compiler-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz", + "integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.14", + "postcss-selector-parser": "^5.0.0", + "prettier": "1.16.3", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "@vue/preload-webpack-plugin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.0.tgz", + "integrity": "sha512-rcn2KhSHESBFMPj5vc5X2pI9bcBNQQixvJXhD5gZ4rN2iym/uH2qfDSQfUS5+qwiz0a85TCkeUs6w6jxFDudbw==", + "dev": true + }, + "@vue/web-component-wrapper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.2.0.tgz", + "integrity": "sha512-Xn/+vdm9CjuC9p3Ae+lTClNutrVhsXpzxvoTXXtoys6kVRX9FkueSUAqSWAyZntmVLlR4DosBV4pH8y5Z/HbUw==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/ast/download/@webassemblyjs/ast-1.7.11.tgz", + "integrity": "sha1-uYhYLK+7Kwlei1VlJvMMkNBXys4=", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/floating-point-hex-parser/download/@webassemblyjs/floating-point-hex-parser-1.7.11.tgz", + "integrity": "sha1-pp8K9lAuuaPARVVbGmEp09Py4xM=", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-api-error/download/@webassemblyjs/helper-api-error-1.7.11.tgz", + "integrity": "sha1-x7a7gQX4QDlRGis5zklPGTgYoyo=", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-buffer/download/@webassemblyjs/helper-buffer-1.7.11.tgz", + "integrity": "sha1-MSLUjcxslFbtmC3r4WyPNxAd85s=", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-code-frame/download/@webassemblyjs/helper-code-frame-1.7.11.tgz", + "integrity": "sha1-z48QbnRmYqDaKb3vY1/NPRJINks=", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-fsm/download/@webassemblyjs/helper-fsm-1.7.11.tgz", + "integrity": "sha1-3ziIKmJAgNA/dQP5Pj8XrFrAEYE=", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-module-context/download/@webassemblyjs/helper-module-context-1.7.11.tgz", + "integrity": "sha1-2HTXIuUeYqwgJHaTXWScgC+g4gk=", + "dev": true + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-wasm-bytecode/download/@webassemblyjs/helper-wasm-bytecode-1.7.11.tgz", + "integrity": "sha1-3ZoegX8cLrEFtM8QEwk8ufPJywY=", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-wasm-section/download/@webassemblyjs/helper-wasm-section-1.7.11.tgz", + "integrity": "sha1-nJrEHs+fvP/8lvbSZ14t4zgR5oo=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/ieee754/download/@webassemblyjs/ieee754-1.7.11.tgz", + "integrity": "sha1-yVg562N1ejGICq7HtlEtQZGsZAs=", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/leb128/download/@webassemblyjs/leb128-1.7.11.tgz", + "integrity": "sha1-1yZ6HunEWU/T9+NymIGOxlaH22M=", + "dev": true, + "requires": { + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/utf8": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/utf8/download/@webassemblyjs/utf8-1.7.11.tgz", + "integrity": "sha1-Btchjqn9yUpnk6qSIIFg2z0m7oI=", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-edit/download/@webassemblyjs/wasm-edit-1.7.11.tgz", + "integrity": "sha1-jHTKR01PlR0B266b1wgU7iKoIAU=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/helper-wasm-section": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-opt": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-gen/download/@webassemblyjs/wasm-gen-1.7.11.tgz", + "integrity": "sha1-m7upQvIjdWhqb7dZr816ycRdoag=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-opt/download/@webassemblyjs/wasm-opt-1.7.11.tgz", + "integrity": "sha1-szHo5874+OLwB9QsOjagWAp9bKc=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-parser/download/@webassemblyjs/wasm-parser-1.7.11.tgz", + "integrity": "sha1-bj0g+mo1GfawhO+Tka1YIR77Cho=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wast-parser/download/@webassemblyjs/wast-parser-1.7.11.tgz", + "integrity": "sha1-Jb0RdWLKjAAnIP+BFu+QctnKhpw=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/floating-point-hex-parser": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-code-frame": "1.7.11", + "@webassemblyjs/helper-fsm": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.7.11", + "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wast-printer/download/@webassemblyjs/wast-printer-1.7.11.tgz", + "integrity": "sha1-xCRbbeJCy1CizJUBdP2/ZceNeBM=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/@xtuc/ieee754/download/@xtuc/ieee754-1.2.0.tgz", + "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.1", + "resolved": "http://registry.npm.taobao.org/@xtuc/long/download/@xtuc/long-4.2.1.tgz", + "integrity": "sha1-XIXWYvdvodNFdXZsXc1mFavNMNg=", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.5", + "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-5.7.3.tgz", + "integrity": "sha1-Z6ojG/iBKXS4UjWpZ3Hra9B+onk=", + "dev": true + }, + "acorn-dynamic-import": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/acorn-dynamic-import/download/acorn-dynamic-import-3.0.0.tgz", + "integrity": "sha1-kBzu5Mf6rvfgetKkfokGddpQong=", + "dev": true, + "requires": { + "acorn": "^5.0.0" + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "optional": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "optional": true + } + } + }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "address": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", + "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==", + "dev": true + }, + "ajv": { + "version": "6.10.0", + "resolved": "http://registry.npm.taobao.org/ajv/download/ajv-6.10.0.tgz", + "integrity": "sha1-kNDVRDnaWHzX6EO/twRfUL0ivfE=", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz", + "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "http://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.4.0.tgz", + "integrity": "sha1-S4Mee1MUFafMUYzUBOc/YZPGNJ0=", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-3.2.0.tgz", + "integrity": "sha1-h4C5j/nb9WOBUtHx/lwde0RCl2s=", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "http://registry.npm.taobao.org/ansi-html/download/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz", + "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" + }, + "arch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz", + "integrity": "sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-filter": { + "version": "0.0.1", + "resolved": "http://registry.npm.taobao.org/array-filter/download/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-map": { + "version": "0.0.0", + "resolved": "http://registry.npm.taobao.org/array-map/download/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "http://registry.npm.taobao.org/array-reduce/download/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "http://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", + "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "http://registry.npm.taobao.org/asn1.js/download/asn1.js-4.10.1.tgz", + "integrity": "sha1-ucK/WAXx5kqt7tbfOiv6+1pz9aA=", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/assert/download/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "http://registry.npm.taobao.org/util/download/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/astral-regex/download/astral-regex-1.0.0.tgz", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "dev": true + }, + "async-each": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/async-each/download/async-each-1.0.2.tgz", + "integrity": "sha1-i4p8oqZY+Sfp8wfW0aQvQZnw9zU=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "requires": { + "babel-runtime": "6.x" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "http://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/atob/download/atob-2.1.2.tgz", + "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", + "dev": true + }, + "autoprefixer": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.5.1.tgz", + "integrity": "sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ==", + "dev": true, + "requires": { + "browserslist": "^4.5.4", + "caniuse-lite": "^1.0.30000957", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.14", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "browserslist": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.5.tgz", + "integrity": "sha512-0QFO1r/2c792Ohkit5XI8Cm8pDtZxgNl2H6HU4mHrpYz7314pEYcsAVVatM0l/YmxPnEzh9VygXouj4gkFUTKA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000960", + "electron-to-chromium": "^1.3.124", + "node-releases": "^1.1.14" + } + }, + "caniuse-lite": { + "version": "1.0.30000962", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000962.tgz", + "integrity": "sha512-WXYsW38HK+6eaj5IZR16Rn91TGhU3OhbwjKZvJ4HN/XBIABLKfbij9Mnd3pM0VEwZSlltWjoWg3I8FQ0DGgNOA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.124", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz", + "integrity": "sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w==", + "dev": true + }, + "node-releases": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.15.tgz", + "integrity": "sha512-cKV097BQaZr8LTSRUa2+oc/aX5L8UkZtPQrMSTgiJEeaW7ymTDCoRaGCoaTqk0lqnalcoSHu4wjSl0Cmj2+bMw==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "http://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "http://registry.npm.taobao.org/aws4/download/aws4-1.8.0.tgz", + "integrity": "sha1-8OAD2cqef1nHpQiUXXsu+aBKVC8=" + }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "http://registry.npm.taobao.org/babel-code-frame/download/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "http://registry.npm.taobao.org/js-tokens/download/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-eslint": { + "version": "10.0.1", + "resolved": "http://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.0.1.tgz", + "integrity": "sha1-kZaB3AmWFM19MdRciQhpUJKh+u0=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "3.7.1", + "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz", + "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==", + "dev": true, + "requires": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/babel-plugin-dynamic-import-node/download/babel-plugin-dynamic-import-node-2.2.0.tgz", + "integrity": "sha1-wK37B9lfSkSV6aqsbsOGxNfCUk4=", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "http://registry.npm.taobao.org/base/download/base-0.11.2.tgz", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "http://registry.npm.taobao.org/base64-js/download/base64-js-1.3.0.tgz", + "integrity": "sha1-yrHmEY8FEJXli1KBrqjBzSK/wOM=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "http://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bfj": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.1.tgz", + "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "check-types": "^7.3.0", + "hoopy": "^0.1.2", + "tryer": "^1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "http://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", + "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=" + }, + "binary-extensions": { + "version": "1.13.0", + "resolved": "http://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.0.tgz", + "integrity": "sha1-lSPgATBqMkRLkHQj8d4hZCIvarE=", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.5.3", + "resolved": "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.3.tgz", + "integrity": "sha1-fQHG+WFsmlGrD4xUmnnf5uwz76c=", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "http://registry.npm.taobao.org/bn.js/download/bn.js-4.11.8.tgz", + "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", + "dev": true + }, + "body-parser": { + "version": "1.18.3", + "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "http://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + }, + "dependencies": { + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "bootstrap": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", + "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==" + }, + "bootstrap-vue": { + "version": "2.0.0-rc.19", + "resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.19.tgz", + "integrity": "sha512-OCbRwqKb0F+RGr162m+RyKI4yNM0VjfxOGI32CMgHfCnnc0MZ0wF2Svg2E3Q7AWCq0N8LgD/EsF/K7Vg3kdDyw==", + "requires": { + "@nuxt/opencollective": "^0.2.2", + "bootstrap": "^4.3.1", + "core-js": ">=2.6.5 <3.0.0", + "popper.js": "^1.15.0", + "portal-vue": "^2.1.1", + "vue-functional-data-merge": "^2.0.7" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "http://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/brorand/download/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/browserify-aes/download/browserify-aes-1.2.0.tgz", + "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/browserify-cipher/download/browserify-cipher-1.0.1.tgz", + "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/browserify-des/download/browserify-des-1.0.2.tgz", + "integrity": "sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw=", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "http://registry.npm.taobao.org/browserify-rsa/download/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "http://registry.npm.taobao.org/browserify-sign/download/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/browserify-zlib/download/browserify-zlib-0.2.0.tgz", + "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.5.2", + "resolved": "http://registry.npm.taobao.org/browserslist/download/browserslist-4.5.2.tgz", + "integrity": "sha1-Nq0oHwQK9oRVWiPHgPXCCBx1LfA=", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000951", + "electron-to-chromium": "^1.3.116", + "node-releases": "^1.1.11" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "http://registry.npm.taobao.org/buffer/download/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", + "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-loader": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-2.0.1.tgz", + "integrity": "sha512-V99T3FOynmGx26Zom+JrVBytLBsmUCzVG2/4NnUKgvXN4bEV42R1ERl1IyiH/cvFIDA1Ytq2lPZ9tXDSahcQpQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.0", + "normalize-path": "^3.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/call-me-maybe/download/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/caller-callsite/download/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "http://registry.npm.taobao.org/caller-path/download/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "optional": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/callsites/download/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true, + "optional": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-5.2.0.tgz", + "integrity": "sha1-51IqvaXtlMwEieG4RmYQ6IQEz0U=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000951", + "resolved": "http://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30000951.tgz", + "integrity": "sha1-x8L9TXEIAoTIZ33UEDaN+Ng2iP4=", + "dev": true + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz", + "integrity": "sha512-u5ElzokS8A1pm9vM3/iDgTcI3xqHxuCao94Oz8etI3cf0Tio0p8izkDYbTIn09uP3yUUr6+veaE6IkjnTYS46g==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "http://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "http://registry.npm.taobao.org/chardet/download/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true, + "optional": true + }, + "chart.js": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz", + "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==", + "requires": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "chartjs-color": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz", + "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==", + "requires": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^0.5.3" + }, + "dependencies": { + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + } + } + }, + "chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "requires": { + "color-name": "^1.0.0" + } + }, + "check-types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz", + "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==", + "dev": true + }, + "chokidar": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/chokidar/download/chokidar-2.1.2.tgz", + "integrity": "sha1-nCPqQLAWOEOeBROGTTYq6sxa0Fg=", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.0" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/chownr/download/chownr-1.1.1.tgz", + "integrity": "sha1-VHJri4//TfBTxCGH6AH7RBLfFJQ=" + }, + "chrome-trace-event": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/chrome-trace-event/download/chrome-trace-event-1.0.0.tgz", + "integrity": "sha1-Rakb0sIMlBHwljtarrmhuV4JzEg=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/cipher-base/download/cipher-base-1.0.4.tgz", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "http://registry.npm.taobao.org/circular-json/download/circular-json-0.3.3.tgz", + "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=", + "dev": true, + "optional": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "http://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/cli-spinners/download/cli-spinners-2.0.0.tgz", + "integrity": "sha1-SweHVvwXqPcgQ/3J8fFL9PqH4t8=", + "dev": true + }, + "cli-width": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/cli-width/download/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "clipboardy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.0.0.tgz", + "integrity": "sha512-XbVjHMsss0giNUkp/tV/3eEAZe8i1fZTLzmPKqjE1RGIAWOTiF5D014f6R+g53ZAq0IK3cPrJXFvqE8eQjhFYQ==", + "dev": true, + "requires": { + "arch": "^2.1.1", + "execa": "^1.0.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/clone/download/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz", + "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "http://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "http://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.7.tgz", + "integrity": "sha1-LR0kMXr7ir6V1tLAsHtXgTU52Cg=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.19.0", + "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.19.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.19.0.tgz", + "integrity": "sha1-9hmKqE5bg8RgVLlN3tv+1e6f8So=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "compressible": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz", + "integrity": "sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA==", + "dev": true, + "requires": { + "mime-db": ">= 1.38.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "http://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "http://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "consola": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.6.1.tgz", + "integrity": "sha512-vt35owQG6OxYDJVaViQ4aFgOK+b98hIvs+R5CWkKgpO8rTPyaYwlMadZ7oZcjnWz1/+u4czDnrcogFr5AtrRug==" + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/console-browserify/download/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/constants-browserify/download/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "http://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.6.0.tgz", + "integrity": "sha1-UbU3qMQ+DwTewZk7/83VBOdYrCA=", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "http://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/copy-concurrently/download/copy-concurrently-1.0.5.tgz", + "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", + "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + }, + "dependencies": { + "cacache": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "globby": { + "version": "7.1.1", + "resolved": "http://registry.npm.taobao.org/globby/download/globby-7.1.1.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/locate-path/download/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/p-locate/download/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/p-try/download/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/pkg-dir/download/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "ssri": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "core-js": { + "version": "2.6.5", + "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-2.6.5.tgz", + "integrity": "sha1-RLyNJJ5/sv9dAOA0Gn/7lPv2eJU=" + }, + "core-js-compat": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/core-js-compat/download/core-js-compat-3.0.0.tgz", + "integrity": "sha1-zZgQuAAHQlNaSkN3OGYYXjEL1Pc=", + "dev": true, + "requires": { + "browserslist": "^4.5.1", + "core-js": "3.0.0", + "core-js-pure": "3.0.0", + "semver": "^5.6.0" + }, + "dependencies": { + "core-js": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-3.0.0.tgz", + "integrity": "sha1-qNv6l40pv8Jjv7ZsVW0MqSTCiVc=", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/core-js-pure/download/core-js-pure-3.0.0.tgz", + "integrity": "sha1-pWea20h1QnyMBIivyT5vW3ElhZs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", + "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.0", + "parse-json": "^4.0.0" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "http://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.3.tgz", + "integrity": "sha1-yREbbzMEXEaX8UR4f5JUzcd8Rf8=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/create-hash/download/create-hash-1.2.0.tgz", + "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "http://registry.npm.taobao.org/create-hmac/download/create-hmac-1.1.7.tgz", + "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz", + "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "http://registry.npm.taobao.org/crypto-browserify/download/crypto-browserify-3.12.0.tgz", + "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "http://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-loader": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.1.tgz", + "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash": "^4.17.11", + "postcss": "^6.0.23", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-select": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", + "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + }, + "dependencies": { + "cssesc": { + "version": "0.1.0", + "resolved": "http://registry.npm.taobao.org/cssesc/download/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "http://registry.npm.taobao.org/jsesc/download/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/regexpu-core/download/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/regjsgen/download/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "http://registry.npm.taobao.org/regjsparser/download/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/css-unit-converter/download/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "current-script-polyfill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz", + "integrity": "sha1-8xz35PPiGLBybnOMqSoC00iO9hU=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "http://registry.npm.taobao.org/cyclist/download/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "http://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "http://registry.npm.taobao.org/date-now/download/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "de-indent": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "http://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "http://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz", + "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M=" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz", + "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/des.js/download/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "http://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz", + "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "http://registry.npm.taobao.org/dir-glob/download/dir-glob-2.2.2.tgz", + "integrity": "sha1-+gnwaUFTyJGLGLoN6vrpR2n8UMQ=", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/doctrine/download/doctrine-2.1.0.tgz", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "dev": true, + "optional": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz", + "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "downloadjs": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", + "integrity": "sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw=" + }, + "duplexer": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "http://registry.npm.taobao.org/duplexify/download/duplexify-3.7.1.tgz", + "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "easy-stack": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/easy-stack/download/easy-stack-1.0.0.tgz", + "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "echarts": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.6.0.tgz", + "integrity": "sha512-xKkcr6v9UVOSF+PMuj7Ngt3bnzLwN1sSXWCvpvX+jYb3mePYsZnABq7wGkPac/m0nV653uGHXoHK8DCKCprdNg==", + "requires": { + "zrender": "4.2.0" + } + }, + "echarts-amap": { + "version": "1.0.0-rc.6", + "resolved": "https://registry.npmjs.org/echarts-amap/-/echarts-amap-1.0.0-rc.6.tgz", + "integrity": "sha1-V4KnTa7lLtRM4/j2JXdWF4PwnhY=" + }, + "echarts-liquidfill": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-2.0.5.tgz", + "integrity": "sha512-3G19W5ngoh1L3BXYuD34g0Vd30ORWvQtyxRuL+7vmOZ3FkF6xkgD4pfcCL7QVAQOr+XZ4OiD2ot6dNGsRhflcg==" + }, + "echarts-wordcloud": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-1.1.3.tgz", + "integrity": "sha512-Et8D5xEAoYkidmHun+hEH+2lF9dhCt6D0JJ390vlr2r/1zwhhZAbcL01CEvG93QcMcJpSvSPK8vRiGkTbMHRxg==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.119", + "resolved": "http://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.119.tgz", + "integrity": "sha1-mndw2mZyUq64H2Z4U/Z8KybgAZc=", + "dev": true + }, + "element-ui": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.13.1.tgz", + "integrity": "sha512-jyvJmXa2c6ElRc4NOw4V1vnjHsvfzTRhbwElZ68CyF9by2F64B+AJRzujg/HJgXCimHwd2g1Av9D04EP3mWymg==", + "requires": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + } + }, + "elliptic": { + "version": "6.4.1", + "resolved": "http://registry.npm.taobao.org/elliptic/download/elliptic-6.4.1.tgz", + "integrity": "sha1-wtC3d2kRuGcixjLDwGxg8vgZk5o=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "http://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz", + "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.1.tgz", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "http://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-4.1.0.tgz", + "integrity": "sha1-Qcfgv9/nSsH/4eV61qXGyfN0Kn8=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "http://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz", + "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.2.tgz", + "integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==", + "dev": true, + "requires": { + "stackframe": "^1.0.4" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "http://registry.npm.taobao.org/es-abstract/download/es-abstract-1.13.0.tgz", + "integrity": "sha1-rIYUX91QmdjdSVWMy6Lq+biOJOk=", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.0.tgz", + "integrity": "sha1-7fckeAM0VujdqO8J4ArZZQcH83c=", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "5.15.3", + "resolved": "http://registry.npm.taobao.org/eslint/download/eslint-5.15.3.tgz", + "integrity": "sha1-x5w5CdyKf6NxT7NAwR4w/SUmuLU=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.12.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "http://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.0.1.tgz", + "integrity": "sha1-MqBk/ZJUKSFqCbFBECv90YX65A4=", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "http://registry.npm.taobao.org/chardet/download/chardet-0.7.0.tgz", + "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "espree": { + "version": "5.0.1", + "resolved": "http://registry.npm.taobao.org/espree/download/espree-5.0.1.tgz", + "integrity": "sha1-XWUm+k/H8HiKXPdbFfMDI+L4H3o=", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "external-editor": { + "version": "3.0.3", + "resolved": "http://registry.npm.taobao.org/external-editor/download/external-editor-3.0.3.tgz", + "integrity": "sha1-WGbbKal4Jtvkvzr9JAcOrZ6kOic=", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "http://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-5.0.1.tgz", + "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/flat-cache/download/flat-cache-2.0.1.tgz", + "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "http://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "dev": true + }, + "import-fresh": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/import-fresh/download/import-fresh-3.0.0.tgz", + "integrity": "sha1-o9iX9CDKsOZxI2iX91vBS0iFw5A=", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inquirer": { + "version": "6.2.2", + "resolved": "http://registry.npm.taobao.org/inquirer/download/inquirer-6.2.2.tgz", + "integrity": "sha1-RpQRdvZcnrIIBGJxSbdDohjyVAY=", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "strip-ansi": { + "version": "5.2.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/regexpp/download/regexpp-2.0.1.tgz", + "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz", + "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz", + "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "table": { + "version": "5.2.3", + "resolved": "http://registry.npm.taobao.org/table/download/table-5.2.3.tgz", + "integrity": "sha1-zeDMbrBnUcAJ76sn6Mggyltnt/I=", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "write": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/write/download/write-1.0.3.tgz", + "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } + } + }, + "eslint-loader": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.2.1.tgz", + "integrity": "sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg==", + "dev": true, + "requires": { + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" + } + }, + "eslint-plugin-vue": { + "version": "5.2.2", + "resolved": "http://registry.npm.taobao.org/eslint-plugin-vue/download/eslint-plugin-vue-5.2.2.tgz", + "integrity": "sha1-hmAYI7dyG3C8ktVPFyjPwDs2KDw=", + "dev": true, + "requires": { + "vue-eslint-parser": "^5.0.0" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "http://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.0.1.tgz", + "integrity": "sha1-MqBk/ZJUKSFqCbFBECv90YX65A4=", + "dev": true + }, + "espree": { + "version": "4.1.0", + "resolved": "http://registry.npm.taobao.org/espree/download/espree-4.1.0.tgz", + "integrity": "sha1-co1UUeD9FWwEOEp62J7VH/VOsl8=", + "dev": true, + "requires": { + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "vue-eslint-parser": { + "version": "5.0.0", + "resolved": "http://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-5.0.0.tgz", + "integrity": "sha1-APTk2pTsl0uCGib/DtD3p4QCuKE=", + "dev": true, + "requires": { + "debug": "^4.1.0", + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.1.0", + "esquery": "^1.0.1", + "lodash": "^4.17.11" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz", + "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "http://registry.npm.taobao.org/espree/download/espree-3.5.4.tgz", + "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", + "dev": true, + "optional": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/esquery/download/esquery-1.0.1.tgz", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "http://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "http://registry.npm.taobao.org/estraverse/download/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/esutils/download/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "http://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-pubsub": { + "version": "4.3.0", + "resolved": "http://registry.npm.taobao.org/event-pubsub/download/event-pubsub-4.3.0.tgz", + "integrity": "sha1-9o2Ba8KfHsAsU53FjI3UDOcss24=", + "dev": true + }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/events/download/events-3.0.0.tgz", + "integrity": "sha1-mgoN+vYok9krh1uPJpjKQRSXPog=", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/evp_bytestokey/download/evp_bytestokey-1.0.3.tgz", + "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/execa/download/execa-1.0.0.tgz", + "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "http://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "http://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/external-editor/download/external-editor-2.2.0.tgz", + "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", + "dev": true, + "optional": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "http://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "http://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-glob": { + "version": "2.2.6", + "resolved": "http://registry.npm.taobao.org/fast-glob/download/fast-glob-2.2.6.tgz", + "integrity": "sha1-pdW2l+yN7aRo2Fp0A1KQoCWpUpU=", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "http://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "http://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "http://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.1.tgz", + "integrity": "sha1-hiRwESkBxyeg5JWoB0S9W6odZ5A=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/figures/download/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "optional": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", + "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "http://registry.npm.taobao.org/flat-cache/download/flat-cache-1.3.4.tgz", + "integrity": "sha1-LC73dSXMKSkAff/6HdMUqpyd7m8=", + "dev": true, + "optional": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "flatted": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/flatted/download/flatted-2.0.0.tgz", + "integrity": "sha1-VRIrZTbqSWtLRIk+4mCBQdENmRY=", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.1.1.tgz", + "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "http://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.7.0.tgz", + "integrity": "sha1-SJ68GY3A5/ZBZ70jsDxMGbV4THY=", + "dev": true, + "requires": { + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "http://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "http://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", + "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "http://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "http://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "requires": { + "minipass": "^2.2.1" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "http://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "dev": true + } + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "http://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz", + "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "http://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "http://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "http://registry.npm.taobao.org/glob/download/glob-7.1.3.tgz", + "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globals": { + "version": "11.11.0", + "resolved": "http://registry.npm.taobao.org/globals/download/globals-11.11.0.tgz", + "integrity": "sha1-3Pk3V/ot5Uhvvu1xGFOK33ienC4=", + "dev": true + }, + "globby": { + "version": "9.1.0", + "resolved": "http://registry.npm.taobao.org/globby/download/globby-9.1.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-9.1.0.tgz", + "integrity": "sha1-6Q9NUTQQnm2FWr3TG9sbCFQoWS4=", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.1", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "http://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "dev": true + } + } + }, + "globule": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.12", + "minimatch": "~3.0.2" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "requires": { + "delegate": "^3.1.2" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.15.tgz", + "integrity": "sha1-/7cD4QZuig7qpMi4C6klPu77+wA=" + }, + "gzip-size": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.0.tgz", + "integrity": "sha512-wfSnvypBDRW94v5W3ckvvz/zFUNdJ81VgOP6tE4bPpRUcc0wGqU+y0eZjJEvKxwubJFix6P84sE8M51YWLT7rQ==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "http://registry.npm.taobao.org/har-validator/download/har-validator-5.1.3.tgz", + "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/has/download/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/has-ansi/download/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "http://registry.npm.taobao.org/hash-base/download/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash-sum": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, + "hash.js": { + "version": "1.1.7", + "resolved": "http://registry.npm.taobao.org/hash.js/download/hash.js-1.1.7.tgz", + "integrity": "sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/he/download/he-1.2.0.tgz", + "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoek": { + "version": "6.1.2", + "resolved": "http://registry.npm.taobao.org/hoek/download/hoek-6.1.2.tgz", + "integrity": "sha1-mebQcFYYOd507kJ7YapHa9a939Y=", + "dev": true + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "http://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/hsl-regex/download/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-entities": { + "version": "1.2.1", + "resolved": "http://registry.npm.taobao.org/html-entities/download/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + } + } + }, + "html-tags": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", + "dev": true + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "http://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "http://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "http://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "dev": true + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/icss-utils/download/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "dev": true, + "requires": { + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "http://registry.npm.taobao.org/ieee754/download/ieee754-1.1.12.tgz", + "integrity": "sha1-UL8k5bnIu5ivSWTJQc2wkY2ntgs=", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "http://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "http://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz", + "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/import-cwd/download/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/import-from/download/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "http://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "http://registry.npm.taobao.org/inquirer/download/inquirer-3.3.0.tgz", + "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", + "dev": true, + "optional": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "http://registry.npm.taobao.org/invariant/download/invariant-2.2.4.tgz", + "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "http://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/ip-regex/download/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "http://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "http://registry.npm.taobao.org/is-callable/download/is-callable-1.1.4.tgz", + "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/is-color-stop/download/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/is-obj/download/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.0.0.tgz", + "integrity": "sha512-m5dHHzpOXEiv18JEORttBO64UgTEypx99vCxQLjbBvGhOJxnTNglYoFXxwo6AbsQb79sqqycQEHv2hWkHZAijA==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.0.0.tgz", + "integrity": "sha512-6Vz5Gc9s/sDA3JBVu0FzWufm8xaBsqy1zn8Q6gmvGP6nSDMw78aS4poBNeatWjaRpTpxxLn1WOndAiOlk+qY8A==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/is-path-inside/download/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "http://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/is-promise/download/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/is-regex/download/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz", + "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.2.tgz", + "integrity": "sha1-oFX2rlcZLK7jKeeoYBGLSXqVDzg=", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isemail": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/isemail/download/isemail-3.2.0.tgz", + "integrity": "sha1-WTEKAhkxqfsGu7UeFVzgs/I2gyw=", + "dev": true, + "requires": { + "punycode": "2.x.x" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "javascript-stringify": { + "version": "1.6.0", + "resolved": "http://registry.npm.taobao.org/javascript-stringify/download/javascript-stringify-1.6.0.tgz", + "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=", + "dev": true + }, + "joi": { + "version": "14.3.1", + "resolved": "http://registry.npm.taobao.org/joi/download/joi-14.3.1.tgz", + "integrity": "sha1-FkomLsC4VUZuDDXuoqiFrotscDw=", + "dev": true, + "requires": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, + "jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" + }, + "js-base64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==" + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "http://registry.npm.taobao.org/js-levenshtein/download/js-levenshtein-1.1.6.tgz", + "integrity": "sha1-xs7ljrNVA3LfjeuF+tXOZs4B1Z0=", + "dev": true + }, + "js-message": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz", + "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", + "dev": true + }, + "js-queue": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/js-queue/download/js-queue-2.0.0.tgz", + "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", + "dev": true, + "requires": { + "easy-stack": "^1.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "http://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz", + "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "http://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "http://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.2", + "resolved": "http://registry.npm.taobao.org/json3/download/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/json5/download/json5-2.1.0.tgz", + "integrity": "sha1-56DGLEgoXGKNIKELhcibuAfDKFA=", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "http://registry.npm.taobao.org/jsonify/download/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "launch-editor": { + "version": "2.2.1", + "resolved": "http://registry.npm.taobao.org/launch-editor/download/launch-editor-2.2.1.tgz", + "integrity": "sha1-hxtaPuOdZoD8wm03kwtu7aidsMo=", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "shell-quote": "^1.6.1" + } + }, + "launch-editor-middleware": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.2.1.tgz", + "integrity": "sha512-s0UO2/gEGiCgei3/2UN3SMuUj1phjQN8lcpnvgLSz26fAzNWPQ6Nf/kF5IFClnfU2ehp6LrmKdMU/beveO+2jg==", + "dev": true, + "requires": { + "launch-editor": "^2.2.1" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "loader-fs-cache": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/loader-fs-cache/download/loader-fs-cache-1.0.1.tgz", + "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/pkg-dir/download/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "http://registry.npm.taobao.org/loader-runner/download/loader-runner-2.4.0.tgz", + "integrity": "sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c=", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "http://registry.npm.taobao.org/loader-utils/download/loader-utils-1.2.3.tgz", + "integrity": "sha1-H/XcaRHJ8KBiUxpMBLYJQGEIwsc=", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz", + "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "http://registry.npm.taobao.org/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "http://registry.npm.taobao.org/lodash.mapvalues/download/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "http://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" + }, + "lodash.transform": { + "version": "4.6.0", + "resolved": "http://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz", + "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "http://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/log-symbols/download/log-symbols-2.2.0.tgz", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "http://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", + "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "http://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz", + "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz", + "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "http://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "http://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz", + "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "http://registry.npm.taobao.org/memory-fs/download/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "http://registry.npm.taobao.org/merge2/download/merge2-1.2.3.tgz", + "integrity": "sha1-fumdvWm7ZIFoklPwGEiKG5ArDtU=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "http://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "http://registry.npm.taobao.org/miller-rabin/download/miller-rabin-4.0.1.tgz", + "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.2.tgz", + "integrity": "sha512-zJBfZDkwRu+j3Pdd2aHsR5GfH2jIWhmL1ZzBoc+X+3JEti2hbArWcyJ+1laC1D2/U/W1a/+Cegj0/OnEU2ybjg==", + "dev": true + }, + "mime-db": { + "version": "1.38.0", + "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.38.0.tgz", + "integrity": "sha1-GiqrFtqesWe0nG5N8tnGjWPY4q0=" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.22.tgz", + "integrity": "sha1-/ms1WhkJJqt2mMmgVWoRGZshmb0=", + "requires": { + "mime-db": "~1.38.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", + "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "^2.0.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/minimalistic-assert/download/minimalistic-assert-1.0.1.tgz", + "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "requires": { + "minipass": "^2.2.1" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/mississippi/download/mississippi-3.0.0.tgz", + "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "http://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "http://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz", + "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "http://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "http://registry.npm.taobao.org/neo-async/download/neo-async-2.6.0.tgz", + "integrity": "sha1-udFeTXHGdikIZUtRg+04t1M0CDU=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz", + "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz", + "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + } + } + }, + "node-ipc": { + "version": "9.1.1", + "resolved": "http://registry.npm.taobao.org/node-ipc/download/node-ipc-9.1.1.tgz", + "integrity": "sha1-TiRe1pOOZRAOWV68XcNLFujdXWk=", + "dev": true, + "requires": { + "event-pubsub": "4.3.0", + "js-message": "1.0.5", + "js-queue": "2.0.0" + } + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/node-libs-browser/download/node-libs-browser-2.2.0.tgz", + "integrity": "sha1-xy9g2dRt4IqUDe27JfP/ovm7qnc=", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.11", + "resolved": "http://registry.npm.taobao.org/node-releases/download/node-releases-1.1.11.tgz", + "integrity": "sha1-mghBpLDZK31RQe0XnnZPQq0icko=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "node-sass": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.0.tgz", + "integrity": "sha512-AxqU+DFpk0lEz95sI6jO0hU0Rwyw7BXVEv6o9OItoXLyeygPeaSpiV4rwQb10JiTghHaa0gZeD21sz+OsQluaw==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/normalize-range/download/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "http://registry.npm.taobao.org/num2fraction/download/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "numerify": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/numerify/-/numerify-1.2.9.tgz", + "integrity": "sha512-X4QzQiytV5ZN3TVLhzbtFzjTarUNnaa1pgNDFqt7u7Nqhxe7FvY2eYrGt4WYHlYXDqgtfC/n/a5nJ2y0LijV8w==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "http://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz", + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "http://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-hash": { + "version": "1.3.1", + "resolved": "http://registry.npm.taobao.org/object-hash/download/object-hash-1.3.1.tgz", + "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=", + "dev": true + }, + "object-keys": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/object-keys/download/object-keys-1.1.0.tgz", + "integrity": "sha1-Eb0iNI3S4JagRasG9shbzDQPoDI=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "http://registry.npm.taobao.org/object.assign/download/object.assign-4.1.0.tgz", + "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "http://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opener": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "http://registry.npm.taobao.org/opn/download/opn-5.5.0.tgz", + "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "http://registry.npm.taobao.org/optionator/download/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "ora": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/ora/download/ora-3.2.0.tgz", + "integrity": "sha1-Z+mKfhH38KyV3qqvEbsE3j0J5IE=", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.0.0", + "wcwidth": "^1.0.1" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/p-defer/download/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/p-limit/download/p-limit-2.2.0.tgz", + "integrity": "sha1-QXyZQeYCepq8ulCS3SkE4lW1+8I=", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/p-try/download/p-try-2.1.0.tgz", + "integrity": "sha1-waDxAw6X3gGLsscYkp0q9ZRj5QU=", + "dev": true + }, + "pako": { + "version": "1.0.10", + "resolved": "http://registry.npm.taobao.org/pako/download/pako-1.0.10.tgz", + "integrity": "sha1-Qyi621CGpCaqkPVBl31JVdpclzI=", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/parallel-transform/download/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/parent-module/download/parent-module-1.0.0.tgz", + "integrity": "sha1-3yUL3FOR9KCF+1idrXYfWta4ZbU=", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/callsites/download/callsites-3.0.0.tgz", + "integrity": "sha1-+361abcq16RYEvk/2UMKPkELPdM=", + "dev": true + } + } + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "http://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.4.tgz", + "integrity": "sha1-N/Zij4I/vesic7TVQENKIvPvH8w=", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/parse-json/download/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "http://registry.npm.taobao.org/path-browserify/download/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "http://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz", + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/path-type/download/path-type-3.0.0.tgz", + "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "http://registry.npm.taobao.org/pbkdf2/download/pbkdf2-3.0.17.tgz", + "integrity": "sha1-l2wgZTBhexTrsyEUI597CTNuk6Y=", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "4.0.1", + "resolved": "http://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", + "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "http://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz", + "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "http://registry.npm.taobao.org/pluralize/download/pluralize-7.0.0.tgz", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "dev": true, + "optional": true + }, + "popper.js": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz", + "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==" + }, + "portal-vue": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.4.tgz", + "integrity": "sha512-Mr2h+RvoOOGHS7N0E3QPP+UQMt1OhSjQ7eMSGTXqkLiO0AjGEDw2x4kzmHATsZfDqQumiaYSDRzlUP2By3lvsA==" + }, + "portfinder": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", + "integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "http://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", + "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "dev": true, + "requires": { + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + } + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", + "dev": true, + "requires": { + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "http://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettier": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", + "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "private": { + "version": "0.1.8", + "resolved": "http://registry.npm.taobao.org/private/download/private-0.1.8.tgz", + "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "http://registry.npm.taobao.org/process/download/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "progress": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.1.31", + "resolved": "http://registry.npm.taobao.org/psl/download/psl-1.1.31.tgz", + "integrity": "sha1-6aqG0BAbWxBcvpOsa3hM1UcnYYQ=" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "http://registry.npm.taobao.org/public-encrypt/download/public-encrypt-4.0.3.tgz", + "integrity": "sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "http://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz", + "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz", + "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" + }, + "q": { + "version": "1.5.1", + "resolved": "http://registry.npm.taobao.org/q/download/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "http://registry.npm.taobao.org/querystring-es3/download/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", + "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/randomfill/download/randomfill-1.0.4.tgz", + "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/range-parser/download/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "read-pkg": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.0.0.tgz", + "integrity": "sha512-OWufaRc67oJjcgrxckW/qO9q22iYzyiONh8h+GMcnOvSHAmhV1Dr3x+gyRjP+Qxc5jKupkSfoCQLS/98rDPh9A==", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "http://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz", + "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "dependencies": { + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "http://registry.npm.taobao.org/regenerate/download/regenerate-1.4.0.tgz", + "integrity": "sha1-SoVuxLVuQHfFV1icroXnpMiGmhE=", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.0.2", + "resolved": "http://registry.npm.taobao.org/regenerate-unicode-properties/download/regenerate-unicode-properties-8.0.2.tgz", + "integrity": "sha1-ezj6opYlI3bTY1WM+9qQyc5wlmI=", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "http://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.2.tgz", + "integrity": "sha1-MuWcmm+5saSv8JtJMMotRHc0NEc=", + "dev": true + }, + "regenerator-transform": { + "version": "0.13.4", + "resolved": "http://registry.npm.taobao.org/regenerator-transform/download/regenerator-transform-0.13.4.tgz", + "integrity": "sha1-GPZ2PPE4LGnDbfdsbOEizGlChPs=", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-tree": { + "version": "0.1.5", + "resolved": "http://registry.npm.taobao.org/regexp-tree/download/regexp-tree-0.1.5.tgz", + "integrity": "sha1-fNcfyhcZjQS0F279eXE/KZgAk5c=", + "dev": true + }, + "regexpp": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/regexpp/download/regexpp-1.1.0.tgz", + "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=", + "dev": true, + "optional": true + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "http://registry.npm.taobao.org/regexpu-core/download/regexpu-core-4.5.4.tgz", + "integrity": "sha1-CA2dAiiaqH/hZnpPUTa8mKauuq4=", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "http://registry.npm.taobao.org/regjsgen/download/regjsgen-0.5.0.tgz", + "integrity": "sha1-p2NNwI+JIJwgSa3aNSVxH7lyZd0=", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "http://registry.npm.taobao.org/regjsparser/download/regjsparser-0.6.0.tgz", + "integrity": "sha1-8eaui32iuulsmTmbhozWyTOiupw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "http://registry.npm.taobao.org/jsesc/download/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "http://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "http://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz", + "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "http://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "http://registry.npm.taobao.org/request/download/request-2.88.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Frequest%2Fdownload%2Frequest-2.88.0.tgz", + "integrity": "sha1-nC/KT301tZLv5Xx/ClXoEFIST+8=", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/request-promise-core/download/request-promise-core-1.1.2.tgz", + "integrity": "sha1-M59qq6vK/bMceZ/xWHADNjAdM0Y=", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "http://registry.npm.taobao.org/request-promise-native/download/request-promise-native-1.0.7.tgz", + "integrity": "sha1-pJhopiS96lBp8SUdCoNuDYmqLFk=", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/require-main-filename/download/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/require-uncached/download/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "optional": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "resolve": { + "version": "1.10.0", + "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.10.0.tgz", + "integrity": "sha1-O9qur0XMB/N1ZW39LlTtCBCxAbo=", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true, + "optional": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "http://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "http://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "http://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz", + "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/ripemd160/download/ripemd160-2.0.2.tgz", + "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "http://registry.npm.taobao.org/run-async/download/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "http://registry.npm.taobao.org/rx-lite/download/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "http://registry.npm.taobao.org/rx-lite-aggregates/download/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "optional": true, + "requires": { + "rx-lite": "*" + } + }, + "rxjs": { + "version": "6.4.0", + "resolved": "http://registry.npm.taobao.org/rxjs/download/rxjs-6.4.0.tgz", + "integrity": "sha1-87sP572n+2nerAwW8XtQsLh5BQQ=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "sass-loader": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", + "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "http://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz", + "integrity": "sha1-unT1l9K+LqiAExdG7hfQoJPGgYc=", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "select-hose": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "http://registry.npm.taobao.org/semver/download/semver-5.6.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.6.0.tgz", + "integrity": "sha1-fnQlb7qknHWqfHogXMInmcrIAAQ=" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.6.1", + "resolved": "http://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-1.6.1.tgz", + "integrity": "sha1-TR9pfsSUKahHym9EKip1USbE2Hk=", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "http://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "http://registry.npm.taobao.org/sha.js/download/sha.js-2.4.11.tgz", + "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "http://registry.npm.taobao.org/shell-quote/download/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "http://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "slash": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/slash/download/slash-2.0.0.tgz", + "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/slice-ansi/download/slice-ansi-1.0.0.tgz", + "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "dev": true, + "optional": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "http://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz", + "integrity": "sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "http://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.2.tgz", + "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "http://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==" + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "http://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", + "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "http://registry.npm.taobao.org/ssri/download/ssri-6.0.1.tgz", + "integrity": "sha1-KjxBso3UW2K2Nnbst0ABJlrp7dg=", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stackframe": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", + "integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/stealthy-require/download/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "http://registry.npm.taobao.org/stream-browserify/download/stream-browserify-2.0.2.tgz", + "integrity": "sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "http://registry.npm.taobao.org/stream-each/download/stream-each-1.2.3.tgz", + "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "http://registry.npm.taobao.org/stream-http/download/stream-http-2.8.3.tgz", + "integrity": "sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw=", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/string.prototype.padend/download/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, + "string.prototype.padstart": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/string.prototype.padstart/download/string.prototype.padstart-3.0.0.tgz", + "integrity": "sha1-W8+tOfRkm7LQMSkuGbzwtRDUskI=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/strip-indent/download/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/svg-tags/download/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + } + }, + "csso": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", + "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", + "dev": true, + "requires": { + "css-tree": "1.0.0-alpha.39" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "dev": true, + "requires": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "dev": true + } + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "table": { + "version": "4.0.2", + "resolved": "http://registry.npm.taobao.org/table/download/table-4.0.2.tgz", + "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", + "dev": true, + "optional": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "http://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true, + "optional": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "optional": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "optional": true + } + } + }, + "tapable": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/tapable/download/tapable-1.1.1.tgz", + "integrity": "sha1-TSl5I8WnKkI2DeKrUtrfquwAAY4=", + "dev": true + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "terser": { + "version": "4.6.13", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.13.tgz", + "integrity": "sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "http://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thread-loader": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-2.1.2.tgz", + "integrity": "sha512-7xpuc9Ifg6WU+QYw/8uUqNdRwMD+N5gjwHKMqETrs96Qn+7BHwECpt2Brzr4HFlf4IAkZsayNhmGdbkBsTJ//w==", + "dev": true, + "requires": { + "loader-runner": "^2.3.1", + "loader-utils": "^1.1.0", + "neo-async": "^2.6.0" + } + }, + "throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npm.taobao.org/through/download/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "http://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz", + "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "http://registry.npm.taobao.org/timers-browserify/download/timers-browserify-2.0.10.tgz", + "integrity": "sha1-HSjj0qrfHVpZlsTp+VYBzQU0gK4=", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "http://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "http://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "topo": { + "version": "3.0.3", + "resolved": "http://registry.npm.taobao.org/topo/download/topo-3.0.3.tgz", + "integrity": "sha1-1aZ/suaTB+vusIQC7Coqb1962Vw=", + "dev": true, + "requires": { + "hoek": "6.x.x" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "http://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "http://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.4.3.tgz", + "integrity": "sha1-U/Nto/R3g7CSWvoG/587FlKA94E=", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "trim-right": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/trim-right/download/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "^7.1.2" + } + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, + "tslib": { + "version": "1.9.3", + "resolved": "http://registry.npm.taobao.org/tslib/download/tslib-1.9.3.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-1.9.3.tgz", + "integrity": "sha1-1+TdeSRdhUKMTX5IIqeZF5VMooY=", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "http://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "http://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "http://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "http://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/unicode-canonical-property-names-ecmascript/download/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/unicode-match-property-ecmascript/download/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/unicode-match-property-value-ecmascript/download/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha1-W0tCbgjROoA2Xg1lesemwexGonc=", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "http://registry.npm.taobao.org/unicode-property-aliases-ecmascript/download/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha1-qcxsx85joKMCP8meNBuUQx1AWlc=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/unique-filename/download/unique-filename-1.1.1.tgz", + "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/unique-slug/download/unique-slug-2.0.1.tgz", + "integrity": "sha1-Xp7cbRzo+yZNsYpQfvm9hURFHKY=", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/unquote/download/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "http://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/upath/download/upath-1.1.2.tgz", + "integrity": "sha1-PbZYYA7a7sy+bbXmhNZ+6MKs0Gg=", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "http://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "http://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz", + "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "http://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "http://registry.npm.taobao.org/url/download/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "url-parse": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.6.tgz", + "integrity": "sha512-/B8AD9iQ01seoXmXf9z/MjLZQIdOoYl/+gvsQF6+mpnxaTfG9P7srYaiqaDMyKkR36XMXfhqSHss5MyFAO8lew==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "http://registry.npm.taobao.org/use/download/use-3.1.1.tgz", + "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "http://registry.npm.taobao.org/util/download/util-0.11.1.tgz", + "integrity": "sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "http://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-lite": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/utils-lite/-/utils-lite-0.1.10.tgz", + "integrity": "sha512-jlHvdtI8MyWURF/3u+ufIjf1Cs5WjN6WZl9qO8dEkZsVjaI7X5YMUhaCFzkvB69ljt6fo4Dd7V/Oj2NJOFDFOQ==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.3.2.tgz", + "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" + }, + "v-charts": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/v-charts/-/v-charts-1.19.0.tgz", + "integrity": "sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==", + "requires": { + "echarts-amap": "1.0.0-rc.6", + "echarts-liquidfill": "^2.0.2", + "echarts-wordcloud": "^1.1.3", + "numerify": "1.2.9", + "utils-lite": "0.1.10" + } + }, + "v-contextmenu": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/v-contextmenu/-/v-contextmenu-2.8.0.tgz", + "integrity": "sha512-Cj5iYDI4R4cwjLKF0vSJChVrQNWUjgV780Fc0gPwZNUxa3ZsRh94whhSOUdGVEURQaapNQ/4RXTqrKB310eGuw==", + "requires": { + "vue": "^2.5.16" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vee-validate": { + "version": "2.2.15", + "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-2.2.15.tgz", + "integrity": "sha512-4TOsI8XwVkKVLkg8Nhmy+jyoJrR6XcTRDyxBarzcCvYzU61zamipS1WsB6FlDze8eJQpgglS4NXAS6o4NDPs1g==" + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "http://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "http://registry.npm.taobao.org/vm-browserify/download/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "vue": { + "version": "2.6.10", + "resolved": "http://registry.npm.taobao.org/vue/download/vue-2.6.10.tgz", + "integrity": "sha1-pysaQqTYKnIepDjRtr9V5mGVxjc=" + }, + "vue-ads-form-builder": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/vue-ads-form-builder/-/vue-ads-form-builder-0.1.15.tgz", + "integrity": "sha512-7J3itnT+MHqODyO39JkGetREA1YlnNVHYj6KGlT9uGMnNr1H7NmTStasoZ1bpHU7AJ5Uyyp7tuWZl105H7DEPw==", + "requires": { + "@fortawesome/fontawesome-free": "^5.7.2", + "vee-validate": "^2.1.7", + "vue": "^2.6.6", + "vue-perfect-scrollbar": "^0.1.0" + } + }, + "vue-ads-pagination": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/vue-ads-pagination/-/vue-ads-pagination-2.1.7.tgz", + "integrity": "sha512-uvWHvHjG3KhdiVeLm4v5DP4K3+MlczizSLCuILNHnWghvt6q6og3L7k8fGuyXFyqMOBftEdV90WU6wRcNCqwtA==", + "requires": { + "@fortawesome/fontawesome-free": "^5.11.2", + "vue": "^2.6.10" + } + }, + "vue-ads-table-tree": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/vue-ads-table-tree/-/vue-ads-table-tree-2.4.2.tgz", + "integrity": "sha512-PBWA1fFw/AdislGkb+zSsvdPQaLrabxymrJq44wsuKIcQUeIWA6bGS/0239XbpsWkuIt6Gtj6yIoSypj5A3qAw==", + "requires": { + "@fortawesome/fontawesome-free": "^5.11.2", + "vue": "^2.6.10", + "vue-ads-form-builder": "^0.1.15", + "vue-ads-pagination": "^2.1.7", + "vue-json-excel": "^0.2.98" + } + }, + "vue-chartjs": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-3.4.2.tgz", + "integrity": "sha512-EhoXUJ17+9isMLhJpOliS++xE5z5FM8iAVytIqnKofByVMr8AISRL/SCy3zvWbvzhjgQPStd9y6adMF5bnWQdg==" + }, + "vue-click-outside": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.0.7.tgz", + "integrity": "sha1-zdKxYF48SUR4TheU6uShKg9wC9Y=" + }, + "vue-clipboard2": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/vue-clipboard2/-/vue-clipboard2-0.3.0.tgz", + "integrity": "sha512-6/Y9NJErWb4LNBLMgsJSdKb7KpF6/jqXagvKlYut6VQzQsNj6515FpwH0r5hhmeJMqaPzf1kxAw8L8Qvw/QBJQ==", + "requires": { + "clipboard": "^2.0.0" + } + }, + "vue-cookies": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.5.13.tgz", + "integrity": "sha512-8pjpXnvbNWx1Lft0t3MJnW+ylv0Wa2Tb6Ch617u/pQah3+SfXUZZdkh3EL3bSpe/Sw2Wdw3+DhycgQsKANSxXg==" + }, + "vue-eslint-parser": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-2.0.3.tgz", + "integrity": "sha1-wmjJbG2Uz+PZOKX3WTlZsMozYNE=", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-3.7.3.tgz", + "integrity": "sha1-u1ByANPRf2AkdjYWC0gmKEsQhTU=", + "dev": true, + "optional": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "vue-functional-data-merge": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz", + "integrity": "sha512-pvLc+H+x2prwBj/uSEIITyxjz/7ZUVVK8uYbrYMmhDvMXnzh9OvQvVEwcOSBQjsubd4Eq41/CSJaWzy4hemMNQ==" + }, + "vue-hot-reload-api": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz", + "integrity": "sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==", + "dev": true + }, + "vue-i18n": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.9.0.tgz", + "integrity": "sha512-8wr/D9yU8CLC8ne9stdQn/N58E7GRSUSO75bCucj2AIFTDyjGfoze5RxFvh2w3e7yxgnz5x+ooOIcoX59PHguQ==" + }, + "vue-json-excel": { + "version": "0.2.98", + "resolved": "https://registry.npmjs.org/vue-json-excel/-/vue-json-excel-0.2.98.tgz", + "integrity": "sha512-hPA3/cOe5nGbEZiJyfpdBIdqBExxF6EhMhpX6vC654PYbTVzdzp7O9ZsC1AgqbgRDR8VjzAaPaEeHg2vGS88FQ==", + "requires": { + "downloadjs": "^1.4.7" + } + }, + "vue-loader": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.0.tgz", + "integrity": "sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^2.5.1", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + } + }, + "vue-perfect-scrollbar": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/vue-perfect-scrollbar/-/vue-perfect-scrollbar-0.1.0.tgz", + "integrity": "sha512-l/ZEidPDFplXeDtxs+gO3D8efhwqyIEcUtfvfRujCQemcn39ghpSNoizWWZYI6Ro0iz3yP+w7LqNxEBjE+T1qQ==" + }, + "vue-router": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz", + "integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg==" + }, + "vue-style-loader": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", + "integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "vue-template-compiler": { + "version": "2.6.10", + "resolved": "http://registry.npm.taobao.org/vue-template-compiler/download/vue-template-compiler-2.6.10.tgz", + "integrity": "sha1-MjtPNJXwT6o1AzN6gvXWUHeZycw=", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "http://registry.npm.taobao.org/watchpack/download/watchpack-1.6.0.tgz", + "integrity": "sha1-S8EsLr6KonenHx0/FNaFx7RGzQA=", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/wcwidth/download/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "4.28.4", + "resolved": "http://registry.npm.taobao.org/webpack/download/webpack-4.28.4.tgz", + "integrity": "sha1-HdrmyJiH1++3Uq3ww80yubB+rNA=", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/wasm-edit": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "acorn": "^5.6.2", + "acorn-dynamic-import": "^3.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^0.4.4", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + } + }, + "webpack-bundle-analyzer": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.7.0.tgz", + "integrity": "sha512-mETdjZ30a3Yf+NTB/wqTgACK7rAYQl5uxKK0WVTNmF0sM3Uv8s3R58YZMW7Rhu0Lk2Rmuhdj5dcH5Q76zCDVdA==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.15", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true + }, + "acorn-walk": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", + "dev": true + } + } + }, + "webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "dev": true, + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" + } + }, + "webpack-dev-server": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz", + "integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.6", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.25", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "loglevel": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz", + "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "requires": { + "node-forge": "0.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "http://registry.npm.taobao.org/webpack-sources/download/webpack-sources-1.3.0.tgz", + "integrity": "sha1-KijcufH0X+lg2PFJMlK17mUw+oU=", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + } + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "http://registry.npm.taobao.org/websocket-driver/download/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "http://registry.npm.taobao.org/which/download/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "http://registry.npm.taobao.org/write/download/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "http://registry.npm.taobao.org/xtend/download/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "http://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz", + "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-3.0.3.tgz", + "integrity": "sha1-tLBJ4xS+VF486AIjbWzSLNkcPek=" + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + } + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "requires": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.8.0", + "resolved": "http://registry.npm.taobao.org/execa/download/execa-0.8.0.tgz", + "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "normalize-path": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-1.0.0.tgz", + "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "zrender": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.2.0.tgz", + "integrity": "sha512-YJ9hxt5uFincYYU3KK31+Ce+B6PJmYYK0Q9fQ6jOUAoC/VHbe4kCKAPkxKeT7jGTxrK5wYu18R0TLGqj2zbEOA==" + } + } +}
diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..aa892a1 --- /dev/null +++ b/frontend/package.json
@@ -0,0 +1,68 @@ +{ + "name": "Jifa", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "dev-build": "vue-cli-service build --mode development --dest build", + "prod-build": "vue-cli-service build --mode production --dest build", + "build": "vue-cli-service build --mode production --dest build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^0.18.1", + "bootstrap-vue": "^2.0.0-rc.19", + "chart.js": "^2.8.0", + "echarts": "^4.6.0", + "element-ui": "^2.13.1", + "font-awesome": "^4.7.0", + "jquery": "^3.4.1", + "node-sass": "^4.14.0", + "popper.js": "^1.15.0", + "sass-loader": "^7.1.0", + "tar": "^4.4.8", + "v-charts": "^1.9.0", + "v-contextmenu": "^2.8.0", + "vue": "^2.6.10", + "vue-ads-table-tree": "^2.4.2", + "vue-chartjs": "^3.4.2", + "vue-click-outside": "^1.0.7", + "vue-clipboard2": "^0.3.0", + "vue-cookies": "^1.5.13", + "vue-i18n": "^8.9.0", + "vue-router": "^3.0.2" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^3.5.0", + "@vue/cli-plugin-eslint": "^3.5.0", + "@vue/cli-service": "^3.6.0", + "babel-eslint": "^10.0.1", + "eslint": "^5.8.0", + "eslint-plugin-vue": "^5.0.0", + "vue-template-compiler": "^2.5.21" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "rules": {}, + "parserOptions": { + "parser": "babel-eslint" + } + }, + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +}
diff --git a/frontend/public/eclipse_incubation_vertical_png.png b/frontend/public/eclipse_incubation_vertical_png.png new file mode 100644 index 0000000..51c6273 --- /dev/null +++ b/frontend/public/eclipse_incubation_vertical_png.png Binary files differ
diff --git a/frontend/public/index.html b/frontend/public/index.html new file mode 100644 index 0000000..bbb1b31 --- /dev/null +++ b/frontend/public/index.html
@@ -0,0 +1,30 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width,initial-scale=1.0"> + <link rel="icon" href="<%= BASE_URL %>eclipse_incubation_vertical_png.png"> + <title data-react-helmet="true">Jifa</title> + <meta name="description" property="og:description" content="Jifa"/> +</head> +<body> +<noscript> + <strong>We're sorry but Jifa doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> +</noscript> +<div id="app"></div> +<!-- built files will be auto injected --> +</body> +</html>
diff --git a/frontend/src/Jifa.css b/frontend/src/Jifa.css new file mode 100644 index 0000000..7cece98 --- /dev/null +++ b/frontend/src/Jifa.css
@@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +:focus { + outline: none; +} + +button:focus { + outline: none; +} + +a:hover { + text-decoration: none; +} + +a:not([href]):not([tabindex]) { + color: #606266; +} + +a:not([href]):not([tabindex]):hover { + color: #409EFF; +} + +a:not([href]):not([tabindex]):focus { + color: #409EFF; +} \ No newline at end of file
diff --git a/frontend/src/Jifa.js b/frontend/src/Jifa.js new file mode 100644 index 0000000..634a3b9 --- /dev/null +++ b/frontend/src/Jifa.js
@@ -0,0 +1,21 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +export default class JifaGlobal { + static prod() { + return process.env.NODE_ENV === 'production' + } + + static dev() { + return process.env.NODE_ENV === 'development' + } +}
diff --git a/frontend/src/Jifa.vue b/frontend/src/Jifa.vue new file mode 100644 index 0000000..c6db415 --- /dev/null +++ b/frontend/src/Jifa.vue
@@ -0,0 +1,25 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <router-view/> +</template> + +<script> + export default {} +</script> + +<style> + html, body { + height: 100%; + } +</style> \ No newline at end of file
diff --git a/frontend/src/assets/eclipse_incubation_vertical_svg.svg b/frontend/src/assets/eclipse_incubation_vertical_svg.svg new file mode 100644 index 0000000..394e6a2 --- /dev/null +++ b/frontend/src/assets/eclipse_incubation_vertical_svg.svg
@@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 210.79 276.54" style="enable-background:new 0 0 210.79 276.54;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#3D3935;} + .st1{fill:#F78D2C;} +</style> +<g> + <path class="st0" d="M43.75,237.34h1.17v15.69h-1.17V237.34z"/> + <path class="st0" d="M48.62,237.34h1.1l10.83,13.65v-13.65h1.12v15.69h-0.87l-11.05-13.94v13.94h-1.12V237.34z"/> + <path class="st0" d="M64.86,245.23v-0.04c0-4.44,3.32-8.11,7.85-8.11c2.8,0,4.48,1.03,6.1,2.51l-0.83,0.85 + c-1.37-1.32-2.94-2.31-5.29-2.31c-3.77,0-6.61,3.07-6.61,7.02v0.04c0,3.97,2.89,7.06,6.63,7.06c2.26,0,3.81-0.88,5.4-2.44 + l0.78,0.76c-1.66,1.64-3.45,2.73-6.23,2.73C68.18,253.3,64.86,249.74,64.86,245.23z"/> + <path class="st0" d="M81.4,246.51v-9.17h1.17v9.06c0,3.7,2,5.83,5.31,5.83c3.18,0,5.22-1.93,5.22-5.72v-9.17h1.17v9.03 + c0,4.51-2.62,6.9-6.43,6.9C84.07,253.28,81.4,250.9,81.4,246.51z"/> + <path class="st0" d="M97.02,237.34h6.48c1.77,0,3.21,0.52,4.08,1.39c0.65,0.65,1.01,1.48,1.01,2.47v0.04 + c0,2.13-1.39,3.21-2.67,3.72c1.88,0.49,3.54,1.57,3.54,3.74v0.04c0,2.62-2.24,4.28-5.63,4.28h-6.81V237.34z M107.4,241.31 + c0-1.73-1.41-2.89-3.92-2.89h-5.29v6.16h5.18c2.35,0,4.03-1.14,4.03-3.23V241.31z M103.5,245.66h-5.31v6.3h5.69 + c2.69,0,4.39-1.23,4.39-3.21v-0.04C108.28,246.78,106.6,245.66,103.5,245.66z"/> + <path class="st0" d="M119.28,237.23h1.12l7.31,15.8h-1.28l-1.99-4.39h-9.26l-1.99,4.39h-1.21L119.28,237.23z M123.94,247.59 + l-4.12-9.08l-4.15,9.08H123.94z"/> + <path class="st0" d="M134.05,238.42h-5.47v-1.08h12.1v1.08h-5.47v14.61h-1.17V238.42z"/> + <path class="st0" d="M144.29,237.34h1.17v15.69h-1.17V237.34z"/> + <path class="st0" d="M148.91,245.23v-0.04c0-4.28,3.16-8.11,7.91-8.11s7.87,3.79,7.87,8.07v0.04c0,4.28-3.16,8.11-7.91,8.11 + S148.91,249.51,148.91,245.23z M163.48,245.23v-0.04c0-3.88-2.82-7.06-6.7-7.06s-6.66,3.14-6.66,7.02v0.04 + c0,3.88,2.82,7.06,6.7,7.06S163.48,249.11,163.48,245.23z"/> + <path class="st0" d="M167.89,237.34h1.1l10.83,13.65v-13.65h1.12v15.69h-0.87l-11.05-13.94v13.94h-1.12V237.34z"/> +</g> +<path class="st1" d="M82.66,189.23c0.85-2.75,3.77-4.8,7.28-4.8c1.2,0,2.31,0.26,3.31,0.68c2.21-1.47,4.94-2.35,7.92-2.35h0.02 + c0.92-1.86,3.29-3.19,6.11-3.19c0.74,0,1.45,0.1,2.12,0.27c-0.09-2.28,0.27-4.66,1.13-7.16c1-2.89,2.45-5.65,3.97-8.4 + c-0.35-4.12-0.62-7.78-5.78-9.28c-1.92-0.56-3.92-0.73-5.88-0.96l-0.01,0l0-0.01c-0.84-0.1-1.68-0.22-2.5-0.38 + c-14.17,14.76-34.15-20.68-34.15-20.68c44.1-6.84,35.81,15.64,35.81,15.64c-3.2-1.56-4.08-3.53-6.52-5.88 + c-5.57-5.35-18.87-6.29-18.87-6.29c15.92,4.07,18.09,11.78,24.35,14.25c1.42,0.32,2.93,0.44,4.38,0.6c2.8,0.3,5.54,0.82,7.87,2.32 + c2.41,1.55,3.49,3.48,4.04,5.65c1.74-3.32,3.24-6.7,3.81-10.34c0.73-4.65,0.06-10.04-3.24-13.85c-3.05-3.52-7.17-6.18-10.43-9.55 + c-3.48-3.61-5.79-8.06-5.88-12.81c-1.76-3.85-4.62-8.32-7.24-10.06C82.9,113.34,67.9,85.58,67.9,85.58 + c34.98-4.88,29.2,13.09,29.2,13.09c-8.4-9.39-18.79-8.55-18.79-8.55c8.4,2.67,15.03,8.03,18.89,11.71l0.53,0.53 + c1.57,1.64,3.17,3.39,4.51,5.27c1.36-5.15,4.53-12.36,7.02-16.66c0,0,8.4-14.82,22.54-24.07c0,0-10.78,1.24-22.39,18.99 + c0,0-15.42-24.19,34.42-28.66c0,0-3.43,43.94-30.38,35.4c-4.68,7.04-7.75,15.11-7.12,20.79c0.62,5.54,4.5,9.44,8.78,13.08 + c1.14-5.84,5.35-10.87,11.54-13.61c4.95-1.97,12.25-3.86,19.07-4.27c0,0-13.33-3.04-23.47,3.89c0,0,0.17-20.29,36.09-5.56 + c0,0-26,26.34-34.35,10.64c-3.96,2.61-6.46,6.99-5.81,11.52c2.32,2.03,4.48,4.22,5.79,6.92c1.83,3.79,2.48,8.21,1.98,12.32 + c-0.96,7.9-5.9,14.62-9.28,21.79c-1.38,2.92-2.7,6.13-2.72,9.37c1.69-0.47,3.52-0.73,5.44-0.73c7.23,0,13.32,3.59,15.29,8.52 + c2.93,0.31,5.24,2.03,5.66,4.21c2.11,1.3,3.78,3.12,4.79,5.24H76.55C78.02,193.62,80.14,190.16,82.66,189.23"/> +<g> + <path class="st0" d="M43.54,206.39h18v3.82H47.8v6.31h12.17v3.81H47.8v6.52h13.91v3.82H43.54V206.39z"/> + <path class="st0" d="M64.55,218.6v-0.07c0-6.9,5.17-12.56,12.52-12.56c4.47,0,7.18,1.56,9.5,3.78l-2.74,3.16 + c-1.94-1.8-4.02-3.02-6.8-3.02c-4.61,0-8.01,3.82-8.01,8.57v0.07c0,4.75,3.36,8.6,8.01,8.6c2.98,0,4.89-1.18,6.97-3.12l2.74,2.77 + c-2.53,2.64-5.31,4.3-9.85,4.3C69.83,231.09,64.55,225.57,64.55,218.6z"/> + <path class="st0" d="M90.22,206.39h4.27v20.39h12.76v3.88H90.22V206.39z"/> + <path class="st0" d="M110.93,206.39h4.27v24.28h-4.27V206.39z"/> + <path class="st0" d="M120.67,206.39h9.57c5.69,0,9.23,3.23,9.23,8.12v0.07c0,5.45-4.37,8.29-9.71,8.29h-4.82v7.8h-4.27V206.39z + M129.9,219.02c3.23,0,5.24-1.8,5.24-4.34v-0.07c0-2.84-2.05-4.33-5.24-4.33h-4.96v8.74H129.9z"/> + <path class="st0" d="M141.21,227.13l2.57-3.05c2.32,2.01,4.68,3.16,7.67,3.16c2.64,0,4.3-1.25,4.3-3.05v-0.07 + c0-1.73-0.97-2.67-5.48-3.71c-5.17-1.25-8.08-2.77-8.08-7.25v-0.07c0-4.16,3.47-7.04,8.29-7.04c3.54,0,6.35,1.08,8.81,3.05 + l-2.29,3.23c-2.19-1.63-4.37-2.5-6.59-2.5c-2.5,0-3.95,1.28-3.95,2.88v0.07c0,1.87,1.11,2.71,5.79,3.82 + c5.13,1.25,7.77,3.09,7.77,7.11v0.07c0,4.54-3.57,7.25-8.67,7.25C147.62,231.02,144.12,229.73,141.21,227.13z"/> + <path class="st0" d="M163.99,206.39h18v3.82h-13.73v6.31h12.17v3.81h-12.17v6.52h13.91v3.82h-18.17V206.39z"/> +</g> +<path class="st1" d="M47.66,62.99c19.6-30.57,58.84-41.24,91.57-26.55c-0.72-0.5-1.45-1.01-2.2-1.49 + c-33.51-21.49-78.05-11.84-99.47,21.57c-21.43,33.4-11.62,77.91,21.89,99.4c0.75,0.48,1.51,0.93,2.27,1.38 + C34.73,133.68,28.06,93.56,47.66,62.99"/> +</svg>
diff --git a/frontend/src/components/404.vue b/frontend/src/components/404.vue new file mode 100644 index 0000000..6f79a09 --- /dev/null +++ b/frontend/src/components/404.vue
@@ -0,0 +1,21 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <div> + 404 + </div> +</template> + +<script> + export default {} +</script> \ No newline at end of file
diff --git a/frontend/src/components/charts/DoughnutChart.js b/frontend/src/components/charts/DoughnutChart.js new file mode 100644 index 0000000..2f0e7ce --- /dev/null +++ b/frontend/src/components/charts/DoughnutChart.js
@@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +import {Doughnut, mixins} from "vue-chartjs"; + +const {reactiveProp} = mixins + +export default { + extends: Doughnut, + mixins: [reactiveProp], + props: ['options'], + mounted() { + this.renderChart(this.chartData, this.options); + } +} \ No newline at end of file
diff --git a/frontend/src/components/finder.vue b/frontend/src/components/finder.vue new file mode 100644 index 0000000..592de5d --- /dev/null +++ b/frontend/src/components/finder.vue
@@ -0,0 +1,347 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-clipboard="http://www.w3.org/1999/xhtml"> + <el-container style="height: 100%"> + <el-dialog + :title="this.getAddFileTitle()" + :visible.sync="transferViewVisible" + width="40%" :close-on-click-modal=false> + <TransferFile :fileType="currentMenuItem" :transferViewVisible="transferViewVisible" + @transferFileFinishNotify="()=>{this.transferViewVisible = false; this.go(1)}" + style="margin-top: -20px"/> + </el-dialog> + + <el-header> + <view-menu subject="finder" + :fileType="currentMenuItem" + :title="this.getAddFileTitle()" + @chooseMenu="item => this.currentMenuItem= item" + @addFile="() => this.transferViewVisible = true"/> + </el-header> + + <el-dialog + :title="$t('jifa.prompt')" + :visible="true" + v-if="fileToDelete" + width="25%" + :before-close="cancelDelete"> + <span style="font-size: 20px; color: #e6a23c"><i class="el-icon-warning"/> </span> + <span style="font-size: 18px">{{ $t('jifa.deletePrompt') }}</span> + <span slot="footer" class="dialog-footer"> + <el-button @click="cancelDelete">{{ $t('jifa.cancel') }}</el-button> + <el-button @click="doDelete" type="primary">{{ $t('jifa.confirm') }}</el-button> + </span> + </el-dialog> + + <el-main v-loading.fullscreen.lock="loading" style="height: 100%"> + <el-row type="flex" v-for="row in rows" :key="row"> + <el-col :span="6" v-for="col in (row < rows ? cols : colsOfLastRow)" :key="col"> + <el-card class="box-card" shadow="hover" style="margin: 20px"> + <div> + <el-row type="flex"> + <el-col :span="16"> + <p style='font-size: 15px; margin:0 auto; white-space: nowrap; text-overflow:ellipsis; overflow:hidden; + color: #606266;'> + <i class="el-icon-document"></i> + {{file(row, col).displayName ? file(row, col).displayName : file(row, col).name}} + </p> + </el-col> + + <el-col :span="8" align="right"> + <span> + <el-link icon="el-icon-document-copy" v-clipboard:copy="file(row, col).name" + :underline="false" target="_blank"/> + </span> + + <span v-if="file(row,col).hasOwnProperty('displayName')"> + <el-divider direction="vertical"></el-divider> + <el-link icon="el-icon-edit" :underline="false" @click="updateFile(file(row,col))"/> + </span> + + <span v-if="file(row,col).hasOwnProperty('shared')"> + <el-divider direction="vertical"></el-divider> + <el-link :icon="file(row, col).shared ? 'el-icon-unlock' : 'el-icon-lock'" + v-on:click="toggleSharedState(file(row, col))" + :underline="false" + target="_blank"/> + </span> + + <span v-if="downloadable(file(row,col))"> + <el-divider direction="vertical"></el-divider> + <el-link icon="el-icon-download" :underline="false" + :href="service('/file/download/' + currentMenuItem + '/' + file(row, col).name)" + target="_blank"/> + </span> + + <span v-if="canDelete(file(row,col))"> + <el-divider direction="vertical"></el-divider> + <el-link icon="el-icon-delete" :underline="false" + v-on:click="fileToDelete = file(row, col).name"/> + </span> + </el-col> + </el-row> + <el-row :align='"middle"' type="flex"> + <el-col :span="12"> + <p style="font-size: 12px; margin: 10px auto 7px; white-space: nowrap; color: #606266;" align="left"> + {{toSizeString(file(row, col).size)}}</p> + </el-col> + <el-col :span="12"> + <p style="font-size: 12px; margin:10px auto 7px; white-space: nowrap; color: #606266;" align="right"> + {{formatDate(new Date(file(row, col).creationTime), "yyyy-MM-dd HH:mm:ss")}}</p> + </el-col> + </el-row> + <el-row> + <hr style="margin: 0 auto 7px;"/> + </el-row> + + <el-row type="flex" justify="space-around" style="margin-bottom: -15px"> + + <el-col :span="8" align="middle" + v-if="file(row, col).transferState === 'NOT_STARTED' || file(row, col).transferState ==='IN_PROGRESS'"> + <el-button type="text"><i class="el-icon-loading"></i> {{$t('jifa.transferring')}}</el-button> + </el-col> + + <el-col :span="8" align="middle" + v-if="file(row, col).transferState === 'ERROR'"> + <el-button type="text"><i class="el-icon-error"></i> {{$t('jifa.transferError')}}</el-button> + </el-col> + + <el-col :span="8" align="middle" + v-if="file(row, col).transferState === 'SUCCESS'"> + <router-link + :to="{path : analysisPath() , query: {file: file(row, col).name, displayName: file(row, col).displayName} }"> + <el-button type="text"><i class="el-icon-view"></i> {{$t('jifa.analyze')}}</el-button> + </router-link> + </el-col> + </el-row> + </div> + </el-card> + </el-col> + </el-row> + + <el-row type="flex" justify="space-around" style="margin-top: 77px"> + <el-col :span="8"> + <el-pagination + background + layout="prev, pager, next" + :current-page="page" + :page-size="pageSize" + :total="totalSize" + @current-change="handleCurrentPageChange" + hide-on-single-page + align="center"> + </el-pagination> + </el-col> + </el-row> + </el-main> + <el-footer> + <Footer/> + </el-footer> + </el-container> +</template> + +<script> + import axios from 'axios' + import Footer from "./footer" + + + import {formatDate} from 'element-ui/src/utils/date-util' + import {service, toSizeString} from '../util' + import TransferFile from './transferFile' + import ViewMenu from './menu/ViewMenu' + + const defaultMenuItem = 'HEAP_DUMP' + + export default { + components: {TransferFile, ViewMenu, Footer}, + data() { + return { + files: [], + cols: 4, + rows: 0, + colsOfLastRow: 0, + + page: 0, + pageSize: 12, + totalSize: 0, + + loading: false, + defaultMenuItem, + + transferViewVisible: false, + fileToDelete: null, + + currentMenuItem: defaultMenuItem, + } + }, + methods: { + getAddFileTitle() { + switch (this.currentMenuItem) { + case "HEAP_DUMP": + return this.$i18n.t('jifa.addHeapDumpFile'); + default: + return this.$i18n.t('jifa.addFile'); + } + }, + + file(row, col) { + return this.files[(row - 1) * this.cols + col - 1] + }, + + service, + formatDate, + toSizeString, + + handleCurrentPageChange(page) { + this.go(page) + }, + + analysisPath() { + let lowered = this.currentMenuItem.toLowerCase().split("_"); + + if (lowered.length === 0) { + return ""; + } else if (lowered.length === 1) { + return lowered[0]; + } + + let finalPath = lowered[0]; + for (let i = 1; i < lowered.length; i++) { + if (lowered[i].length === 0) { + continue; + } + finalPath += lowered[i][0].toUpperCase(); + if (lowered[i].length > 1) { + finalPath += lowered[i].substring(1); + } + } + return finalPath; + }, + + go(page) { + this.page = page + this.fetchFiles() + }, + + toggleSharedState(file) { + let formData = new FormData() + formData.append('name', file.name) + axios.post(service(file.shared ? "/file/unsetShared" : "/file/setShared"), + new URLSearchParams(formData)).then(() => { + file.shared = !file.shared + }) + }, + + downloadable(file) { + return file.downloadble && this.transferIsSuccess(file) + }, + + transferIsSuccess(file) { + return file.transferState === 'SUCCESS' + }, + + canDelete(file) { + return file.transferState === 'SUCCESS' || file.transferState === 'ERROR' + }, + + cancelDelete() { + this.fileToDelete = null + this.$message({ + type: 'info', + message: this.$t('jifa.deleteCanceled'), + duration: 1000 + }); + }, + + doDelete() { + if (!this.fileToDelete) { + return + } + let formData = new FormData() + formData.append('type', this.currentMenuItem) + formData.append('name', this.fileToDelete) + axios.post(service("/file/delete"), new URLSearchParams(formData)).then(() => { + this.fileToDelete = null + this.$message({ + message: this.$t('jifa.deleteSuccessPrompt'), + type: 'success', + duration: 500, + onClose: () => { + if (this.files.length === 1) { + this.go(this.page > 1 ? this.page - 1 : this.page) + } else { + this.go(this.page) + } + } + }); + }).catch(() => { + this.fileToDelete = null + this.$message({ + message: this.$t('jifa.deleteFailedPrompt'), + type: 'error', + duration: 1000 + }); + }) + }, + + fetchFiles() { + this.loading = true; + axios.get(service('/files'), { + params: { + type: this.currentMenuItem, + page: this.page, + pageSize: this.pageSize + } + }).then(resp => { + this.files = resp.data.data + this.totalSize = resp.data.totalSize + if (this.files.length > 0) { + this.rows = Math.ceil(this.files.length / this.cols) + let mod = this.files.length % this.cols + this.colsOfLastRow = mod > 0 ? mod : this.cols + } else { + this.rows = 0 + this.colsOfLastRow = 0 + } + this.loading = false + }) + }, + + updateFile(file) { + this.$prompt('New display name: ', 'Edit', { + confirmButtonText: this.$t("jifa.confirm"), + cancelButtonText: this.$t('jifa.cancel'), + inputValue: file.displayName + }).then(({value}) => { + let formData = new FormData() + formData.append('name', file.name) + formData.append('displayName', value) + axios.post(service("/file/updateDisplayName"), new URLSearchParams(formData)) + .then(() => { + this.go(this.page) + }) + }) + } + }, + + watch: { + currentMenuItem() { + this.go(1) + }, + }, + + created() { + this.go(1) + } + } +</script>
diff --git a/frontend/src/components/footer.vue b/frontend/src/components/footer.vue new file mode 100644 index 0000000..28db119 --- /dev/null +++ b/frontend/src/components/footer.vue
@@ -0,0 +1,18 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> +</template> + +<script> + export default {} +</script>
diff --git a/frontend/src/components/heapdump/ClassLoaders.vue b/frontend/src/components/heapdump/ClassLoaders.vue new file mode 100644 index 0000000..84e7ea2 --- /dev/null +++ b/frontend/src/components/heapdump/ClassLoaders.vue
@@ -0,0 +1,259 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div style="height: 100%"> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-item divider></v-contextmenu-item> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <el-table ref="recordTable" + :data="tableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + :load="loadChildren" + lazy + :span-method="spanMethod" + height="100%" + :indent=8 + v-loading="loading" + > + <el-table-column label="Class Name"> + <template slot-scope="scope"> + <span v-if="scope.row.isRecord" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu> + <img :src="scope.row.classLoader ? (scope.row.hasParent ? classLoaderOutboundIcon : classLoaderIcon) : classIcon"/> + <strong>{{ scope.row.prefix }}</strong> + {{scope.row.label}} + </span> + + <span v-if="scope.row.isSummary"> + <img :src="sumIcon" v-if="records.length >= totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchClassLoaders" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{totalSize}} + </span> + + <span v-if="scope.row.isChildrenSummary"> + <img :src="sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="sumPlusIcon" + @dblclick="fetchChildren(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + </template> + </el-table-column> + + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column label="Defined Classes" prop="definedClasses"> + </el-table-column> + + <el-table-column label="No. of Instances" prop="numberOfInstances"> + </el-table-column> + </el-table> + </div> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + import {ICONS} from "./IconHealper"; + + let rowKey = 1 + export default { + props: ['file'], + methods: { + spanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 6] + } else if (index >= 1 && index <= 5) { + return [0, 0] + } + return [1, 1] + }, + fetchSummary() { + this.loading = true + axios.get(heapDumpService(this.file, 'classLoaderExplorer/summary')).then(resp => { + this.definedClasses = resp.data.definedClasses + this.numberOfInstances = resp.data.numberOfInstances + this.totalSize = resp.data.totalSize + if (this.totalSize > 0) { + this.fetchClassLoaders() + } + }) + }, + fetchClassLoaders() { + this.loading = true + axios.get(heapDumpService(this.file, 'classLoaderExplorer/classLoader'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + let records = resp.data.data + records.forEach(record => this.records.push({ + rowKey: rowKey++, + + objectId: record.objectId, + prefix: record.prefix, + label: record.label, + classLoader: record.classLoader, + hasParent: record.hasParent, + definedClasses: record.definedClasses, + numberOfInstances: record.numberOfInstances, + + hasChildren: record.classLoader, + isRecord: true, + })) + + this.tableData = this.records.concat({ + rowKey: rowKey++, + definedClasses: this.definedClasses, + numberOfInstances: this.numberOfInstances, + isSummary: true + }) + + this.nextPage++ + this.loading = false + }) + }, + + loadChildren(tree, treeNode, resolve) { + this.fetchChildren(tree.rowKey, tree.objectId, 1, resolve) + }, + + fetchChildren(parentRowKey, objectId, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'classLoaderExplorer/children'), { + params: { + classLoaderId: objectId, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['recordTable'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(record => { + loaded.push({ + rowKey: rowKey++, + + objectId: record.objectId, + prefix: record.prefix, + label: record.label, + classLoader: record.classLoader, + hasParent: record.hasParent, + definedClasses: record.classLoader ? record.definedClasses : null, + numberOfInstances: record.numberOfInstances, + + hasChildren: record.classLoader, + + isRecord: true, + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isChildrenSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + }, + data() { + return { + classIcon: ICONS.objects.class, + classLoaderIcon: ICONS.objects.classloader_obj, + classLoaderOutboundIcon: ICONS.objects.out.classloader_obj, + + sumIcon: ICONS.misc.sumIcon, + sumPlusIcon: ICONS.misc.sumPlusIcon, + + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + + loading: false, + + definedClasses: 0, + numberOfInstances: 0, + + totalSize: 0, + nextPage: 1, + pageSize: 25, + records: [], + tableData: [], + + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + } + }, + created() { + this.fetchSummary() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/ColorHelper.js b/frontend/src/components/heapdump/ColorHelper.js new file mode 100644 index 0000000..bc76413 --- /dev/null +++ b/frontend/src/components/heapdump/ColorHelper.js
@@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +export const PIE_COLORS = [ + [96, 127, 143], + [98, 146, 147], + [110, 138, 79], + [140, 101, 87], + [123, 96, 114], + [101, 129, 120], + [148, 132, 75], + [150, 103, 110], + + [152, 173, 183], + [154, 185, 185], + [162, 180, 141], + [181, 156, 147], + [170, 152, 164], + [156, 175, 168], + [186, 176, 139], + [188, 157, 162], + + [68, 105, 125], + [21, 101, 112], + [85, 118, 48], + [119, 74, 57], + [100, 68, 89], + [73, 108, 96], + [129, 110, 44], + [132, 76, 84] +] + +export const REMAINDER_COLOR= [220, 220, 220] + +export function a2rgb(c) { + let r = c[0] + let g = c[1] + let b = c[2] + return '#' + r.toString(16) + g.toString(16) + b.toString(16) +} +
diff --git a/frontend/src/components/heapdump/CommonType.js b/frontend/src/components/heapdump/CommonType.js new file mode 100644 index 0000000..6110ba2 --- /dev/null +++ b/frontend/src/components/heapdump/CommonType.js
@@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +export const OBJECT_TYPE = { + CLASS: 1, + CLASSLOADER: 2, + ARRAY: 3, + NORMAL: 4 +} + +export const CLASS_TYPE = { + NEW: 0, + MIXED: 1, + OLD_FAD: 2 +} \ No newline at end of file
diff --git a/frontend/src/components/heapdump/DirectByteBuffer.vue b/frontend/src/components/heapdump/DirectByteBuffer.vue new file mode 100644 index 0000000..c79f186 --- /dev/null +++ b/frontend/src/components/heapdump/DirectByteBuffer.vue
@@ -0,0 +1,161 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div style="height: 100%"> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <el-table :data="tableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :span-method="spanMethod" + height="100%" + :indent=8 + v-loading="loading" + > + <el-table-column label="Label"> + <template slot-scope="scope"> + <span v-if="scope.row.isRecord" @click="$emit('setSelectedObjectId', scope.row.objectId)" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu + style="cursor: pointer"> + <img :src="instanceIcon"/> {{scope.row.label}} + </span> + + <span v-if="scope.row.isSummary"> + <img :src="sumIcon" v-if="records.length >= totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchRecords" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column label="position" prop="position"> + </el-table-column> + + <el-table-column label="limit" prop="limit"> + </el-table-column> + + <el-table-column label="capacity" prop="capacity"> + </el-table-column> + + </el-table> + </div> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + + let rowKey = 1 + export default { + props: ['file'], + methods: { + spanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 4] + } else if (index >= 1 && index <= 3) { + return [0, 0] + } + return [1, 1] + }, + fetchSummary() { + this.loading = true + axios.get(heapDumpService(this.file, 'directByteBuffer/summary')).then(resp => { + this.totalSize = resp.data.totalSize + this.position = resp.data.position + this.limit = resp.data.limit + this.capacity = resp.data.capacity + if (this.totalSize > 0) { + this.fetchRecords() + } else { + this.loading = false + } + }) + }, + fetchRecords() { + this.loading = true + axios.get(heapDumpService(this.file, 'directByteBuffer/records'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + let records = resp.data.data + records.forEach(record => this.records.push({ + rowKey: rowKey++, + + objectId: record.objectId, + label: record.label, + position: record.position, + limit: record.limit, + capacity: record.capacity, + + isRecord: true, + })) + + this.tableData = this.records.concat({ + rowKey: rowKey++, + position: this.position, + limit: this.limit, + capacity: this.capacity, + isSummary: true + }) + + this.nextPage++ + this.loading = false + }) + }, + }, + data() { + return { + instanceIcon: require('../../assets/heap/objects/instance_obj.gif'), + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + + loading: false, + + position: 0, + limit: 0, + capacity: 0, + + totalSize: 0, + nextPage: 1, + pageSize: 25, + records: [], + tableData: [], + + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + } + }, + created() { + this.fetchSummary() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/DominatorTree.vue b/frontend/src/components/heapdump/DominatorTree.vue new file mode 100644 index 0000000..414c9d5 --- /dev/null +++ b/frontend/src/components/heapdump/DominatorTree.vue
@@ -0,0 +1,268 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div style="height: 100%; position: relative"> + <div style="height: 40px; padding-top: 10px" align="center"> + <el-radio-group v-model="grouping" @change="changeGrouping"> + <el-radio label="NONE">Object</el-radio> + <el-radio label="BY_CLASS">Class</el-radio> + <!--<el-radio label="BY_CLASSLOADER">Class Loader</el-radio>--> + <!--<el-radio label="BY_PACKAGE">Package</el-radio>--> + </el-radio-group> + </div> + + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-item divider></v-contextmenu-item> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <div v-loading="loading" style="position: absolute; top: 40px; left: 0; right: 0; bottom: 0;"> + <el-table + ref='recordTable' :data="tableData" + :highlight-current-row="true" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + :load="loadChildren" + height="100%" + :span-method="spanMethod" + :indent=8 + lazy + fit> + <el-table-column label="Class Name" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isResult" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu> + <img :src="scope.row.icon" style="margin-right: 5px"/> + {{ scope.row.label }} + <span style="font-weight: bold; color: #909399"> + {{ scope.row.suffix }} + </span> + </span> + + <span v-if="scope.row.isSummaryItem"> + <img :src="ICONS.misc.sumIcon" v-if="records.length >= totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchNextPageData" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{totalSize}} + </span> + + <span v-if="scope.row.isChildrenSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchChildren(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + </template> + </el-table-column> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column v-if="grouping!=='NONE'" label="Objects"> + <template slot-scope="scope"> + {{ grouping !== "NONE" ? scope.row.objects : ''}} + </template> + </el-table-column> + + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + <el-table-column label="Retained Heap" prop="retainedHeap"> + </el-table-column> + <el-table-column label="Percentage" prop="percent"> + </el-table-column> + </el-table> + </div> + </div> +</template> + +<script> + import axios from 'axios' + import {getIcon, ICONS} from "./IconHealper"; + import {heapDumpService} from "../../util"; + + let rowKey = 1 + + export default { + props: ['file'], + data() { + return { + ICONS, + loading: false, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + grouping: 'NONE', + + nextPage: 1, + pageSize: 25, + totalSize: 0, + records: [], + tableData: [], + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + } + }, + methods: { + spanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 6] + } else if (index >= 1 && index <= 5) { + return [0, 0] + } + return [1, 1] + }, + clear() { + this.nextPage = 1 + this.totalSize = 0 + this.records = [] + }, + changeGrouping() { + this.clear() + this.fetchNextPageData() + }, + getIconWrapper(gCRoot, objectType) { + if (this.grouping === 'BY_CLASS') { + return ICONS.objects.class + } + return getIcon(gCRoot, objectType) + }, + loadChildren(tree, treeNode, resolve) { + this.fetchChildren(tree.rowKey, tree.objectId, 1, resolve) + }, + fetchChildren(parentRowKey, objectId, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'dominatorTree/children'), { + params: { + parentObjectId: objectId, + page: page, + pageSize: this.pageSize, + grouping: this.grouping + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['recordTable'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + objectId: d.objectId, + icon: this.getIconWrapper(d.gCRoot, d.objectType), + label: d.label, + suffix: d.suffix, + objects: d.objects, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + percent: (d.percent * 100).toFixed(2) + '%', + hasChildren: true, + isResult: true + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isChildrenSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + fetchNextPageData() { + this.loading = true + axios.get(heapDumpService(this.file, 'dominatorTree/roots'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + grouping: this.grouping + } + }).then(resp => { + this.totalSize = resp.data.totalSize + let data = resp.data.data + data.forEach(d => { + this.records.push({ + rowKey: rowKey++, + objectId: d.objectId, + icon: this.getIconWrapper(d.gCRoot, d.objectType), + label: d.label, + suffix: d.suffix, + objects: d.objects, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + percent: (d.percent * 100).toFixed(2) + '%', + hasChildren: this.grouping !== 'BY_CLASS', + isResult: true + }) + }) + this.tableData = this.records.concat({ + rowKey: rowKey++, + isSummaryItem: true + }) + this.nextPage++ + this.loading = false + }) + }, + }, + created() { + this.fetchNextPageData() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/DuplicatedClasses.vue b/frontend/src/components/heapdump/DuplicatedClasses.vue new file mode 100644 index 0000000..64eec6c --- /dev/null +++ b/frontend/src/components/heapdump/DuplicatedClasses.vue
@@ -0,0 +1,209 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <div style="height: 100%"> + <el-table + ref="table" + :data="records" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + height="100%" + :indent=8 + lazy + v-loading="loading" + :load="fetchClassLoaders" + :span-method="tableSpanMethod"> + <el-table-column label="Class Name / Class Loader" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isClassItem"> + <img :src="ICONS.objects.class"/> {{scope.row.label}} + </span> + + <span v-if="scope.row.isClassLoaderItem" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon"/> {{scope.row.label}} + <span style="font-weight: bold; color: #909399" v-if="scope.row.suffix">{{ " " + scope.row.suffix}}</span> + </span> + + <span v-if="scope.row.isCldSummaryItem"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchMoreClassLoaders(scope.row)" style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + + <span v-if="scope.row.isSummaryItem"> + <img :src="ICONS.misc.sumIcon" v-if="currentSize >= totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchDuplicatedClasses" style="cursor: pointer" v-else/> + {{ currentSize }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column label="ClassLoader Counts" prop="classLoaderCount"> + </el-table-column> + + <el-table-column label="Defined Classes" prop="definedClassesCount"> + </el-table-column> + + <el-table-column label="Num of Instances" prop="instantiatedObjectsCount"> + </el-table-column> + </el-table> + + </div> +</template> + +<script> + + import axios from 'axios' + import {heapDumpService} from '../../util' + import {getIcon, ICONS} from "./IconHealper"; + import {OBJECT_TYPE} from './CommonType' + + let rowKey = 1 + export default { + props: ['file'], + methods: { + tableSpanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 4] + } else if (index >= 1 && index <= 3) { + return [0, 0] + } + return [1, 1] + }, + doFetchClassLoaders(parentRowKey, index, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'duplicatedClasses/classLoaders'), { + params: { + index: index, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0 + let loaded = this.$refs['table'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + let res = resp.data.data + for (let i = 0; i < res.length; i++) { + loaded.push({ + rowKey: rowKey++, + isClassLoaderItem: true, + label: res[i].label, + objectId: res[i].objectId, + suffix: res[i].suffix, + definedClassesCount: res[i].definedClassesCount, + instantiatedObjectsCount: res[i].instantiatedObjectsCount, + icon: getIcon(res[i].gCRoot, OBJECT_TYPE.CLASSLOADER) + }) + } + loaded.push({ + rowKey: rowKey++, + parentRowKey: parentRowKey, + isCldSummaryItem: true, + index: index, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + fetchMoreClassLoaders(summary) { + this.doFetchClassLoaders(summary.parentRowKey, summary.index, summary.nextPage, summary.resolve) + }, + fetchClassLoaders(tree, treeNode, resolve) { + this.doFetchClassLoaders(tree.rowKey, tree.index, 1, resolve) + }, + fetchDuplicatedClasses() { + this.loading = true + if (this.nextPage > 1) { + this.records.splice(this.records.length - 1, 1) + } + axios.get(heapDumpService(this.file, 'duplicatedClasses/classes'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + this.totalSize = resp.data.totalSize + let res = resp.data.data + let index = this.currentSize + let tmp = [] + for (let i = 0; i < res.length; i++) { + tmp.push({ + rowKey: rowKey++, + label: res[i].label, + icon: this.classIcon, + index: index++, + classLoaderCount: res[i].count, + currentSize: 0, + hasChildren: res[i].count > 0, + isClassItem: true, + }) + } + this.nextPage++ + this.currentSize += res.length + tmp.forEach(t => this.records.push(t)) + if (this.records.length > 0) { + this.records.push({ + rowKey: rowKey++, + isSummaryItem: true + }) + } + this.loading = false + }) + }, + + }, + data() { + return { + ICONS, + loading: true, + records: [], + nextPage: 1, + pageSize: 25, + currentSize: 0, + totalSize: 0, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + } + }, + created() { + this.fetchDuplicatedClasses() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/DynamicResultSlot.vue b/frontend/src/components/heapdump/DynamicResultSlot.vue new file mode 100644 index 0000000..5e40a63 --- /dev/null +++ b/frontend/src/components/heapdump/DynamicResultSlot.vue
@@ -0,0 +1,557 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div class="resultDiv"> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-item divider></v-contextmenu-item> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab" style="height: 100%"> + <el-tab-pane + v-for="(item) in editableTabs" + :key="item.name" + :label="item.title" + :name="item.name"> + <el-table v-if="item.isObjRefsTab" + ref="resultContainer" + v-loading="item.loading" + :data="item.topItems" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + :load="item.load" + row-key="rowKey" + lazy + :indent=8 + height="100%"> + <el-table-column label="Class Name" width="1000px" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isResult" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu> + <img :src="scope.row.icon" style="margin-right: 5px"/> + <strong>{{ scope.row.prefix }}</strong> + {{ scope.row.label }} + <span style="font-weight: bold; color: #909399"> + {{ scope.row.suffix }} + </span> + </span> + + <span v-if="scope.row.isBoundsSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchObjBounds(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + </template> + </el-table-column> + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + <el-table-column label="Retained Heap" prop="retainedHeap"> + </el-table-column> + </el-table> + + + <el-table v-if="item.isClassRefsTab" + ref="resultContainer" + v-loading="item.loading" + :data="item.topItems" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + :load="item.load" + row-key="rowKey" + lazy + :indent=8 + height="100%"> + <el-table-column label="Class Name" width="1000px" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isResult" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu> + <img :src="scope.row.icon" style="margin-right: 5px"/> + {{ scope.row.label }} + </span> + + <span v-if="scope.row.isBoundsSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchClassBounds(scope.row.parentRowKey, scope.row.objectIds, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + </template> + </el-table-column> + <el-table-column label="Objects" prop="objects"> + </el-table-column> + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + </el-table> + + <div v-if="item.isPathToGCRootsTab" style="height: 100%; overflow: scroll"> + <el-tree ref="resultContainer" + v-loading="item.loading" + :data="item.treeData" + node-key="objectId" + :expand-on-click-node="false" + default-expand-all> + <span class="custom-tree-node" style="font-size: 12px" slot-scope="{ node, data }" + @click="$emit('setSelectedObjectId', data.objectId)" + @contextmenu="contextMenuTargetObjectId = data.objectId; contextMenuTargetObjectLabel = data.label" + v-contextmenu:contextmenu> + <span> + <img :src="data.origin ? getIcon(data.gCRoot, data.objectType) : getInboundIcon(data.gCRoot, data.objectType)" + style="margin-right: 5px"/> + <strong>{{ data.prefix }}</strong> + {{ data.label }} + <span style="font-weight: bold; color: #909399"> + {{ data.suffix }} + </span> + </span> + + <span> + {{ data.shallowSize }} / {{ data.retainedSize }} + </span> + </span> + </el-tree> + <el-divider><i v-if="item.hasMore" :class="item.loading ? 'el-icon-loading':'el-icon-circle-plus-outline'" + style="font-size: 25px; cursor: pointer" + @dblclick="loadMorePathToGCRootsOfObj(item)"></i></el-divider> + </div> + </el-tab-pane> + </el-tabs> + </div> +</template> +<script> + import axios from 'axios' + import { + getClassRefInboundIcon, + getClassRefOutboundIcon, + getIcon, + getInboundIcon, + getOutboundIcon, + ICONS + } from "./IconHealper"; + import {heapDumpService} from "../../util"; + + let rowKey = 1 + + export default { + props: ['file'], + data() { + return { + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + tabIndex: 0, + editableTabsValue: null, + editableTabs: [], + ICONS, + pageSize: 25, + + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + } + }, + methods: { + getIcon, + getInboundIcon, + getOutboundIcon, + currentIndex() { + for (let i = 0; i < this.editableTabs.length; i++) { + if (this.editableTabs[i].name === this.editableTabsValue) { + return i; + } + } + }, + buildTitle(prefix, label) { + return '「' + prefix + '」' + label + }, + + loadObjBounds(tree, treeNode, resolve) { + this.fetchObjBounds(tree.rowKey, tree.objectId, 1, resolve) + }, + + fetchObjBounds(parentRowKey, objectId, page, resolve) { + let index = this.currentIndex() + let tab = this.editableTabs[index] + let outbound = tab.outbound + let table = this.$refs.resultContainer[index] + tab.loading = true + axios.get(heapDumpService(this.file, outbound ? 'outbounds' : 'inbounds'), { + params: { + objectId: objectId, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = table.store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + icon: outbound ? getOutboundIcon(d.gCRoot, d.objectType) : getInboundIcon(d.gCRoot, d.objectType), + prefix: d.prefix, + label: d.label, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + hasChildren: true, + objectId: d.objectId, + isResult: true + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isBoundsSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + tab.loading = false + }) + }, + + outgoingRefsOfObj(objectId, label) { + this.boundsOfObj(objectId, label, true) + }, + + incomingRefsOfObj(objectId, label) { + this.boundsOfObj(objectId, label, false) + }, + + boundsOfObj(objectId, label, outbound) { + let newTabName = ++this.tabIndex + ''; + let newTab = this.addObjRefsTab(this.buildTitle(this.$t(outbound ? + 'jifa.heap.ref.object.outgoing' : 'jifa.heap.ref.object.incoming'), label), + newTabName, this.loadObjBounds, outbound) + newTab.loading = true + axios.get(heapDumpService(this.file, 'object'), { + params: { + objectId: objectId + } + }).then((resp) => { + let topItems = []; + let d = resp.data + topItems.push( + { + rowKey: rowKey++, + icon: outbound ? getOutboundIcon(d.gCRoot, d.objectType) : getIcon(d.gCRoot, d.objectType), + label: d.label, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + hasChildren: true, + objectId: d.objectId, + isResult: true + } + ) + newTab.topItems = topItems + newTab.loading = false + } + ) + }, + + addObjRefsTab(title, name, load, outbound) { + this.tabIndex++; + let newTab = { + title: title, + name: name, + loading: false, + topItems: [], + load: load, + outbound: outbound, + isObjRefsTab: true + } + this.editableTabs.push(newTab) + this.editableTabsValue = name; + return newTab + }, + + loadClassBounds(tree, treeNode, resolve) { + this.fetchClassBounds(tree.rowKey, tree.objectIds, 1, resolve) + }, + + fetchClassBounds(parentRowKey, objectIds, page, resolve) { + let index = this.currentIndex() + let tab = this.editableTabs[index] + let outbound = tab.outbound + let table = this.$refs.resultContainer[index] + tab.loading = true + axios.get(heapDumpService(this.file, outbound ? 'classReference/outbounds/children' : 'classReference/inbounds/children'), { + params: { + objectIds: JSON.stringify(objectIds), + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = table.store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(record => { + loaded.push({ + rowKey: rowKey++, + label: record.label, + hasChildren: true, + objectId: record.objectId, + objectIds: record.objectIds, + objects: record.objects, + shallowHeap: record.shallowSize, + icon: outbound ? getClassRefOutboundIcon(record.type) : getClassRefInboundIcon(record.type), + isResult: true + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectIds: objectIds, + parentRowKey: parentRowKey, + isBoundsSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + tab.loading = false + }) + }, + + outgoingRefsOfClass(objectId, label) { + this.boundsOfClass(objectId, label, true) + }, + + incomingRefsOfClass(objectId, label) { + this.boundsOfClass(objectId, label, false) + }, + + boundsOfClass(id, label, outbound) { + let newTabName = ++this.tabIndex + ''; + let newTab = this.addClassRefsTab(this.buildTitle(this.$t(outbound ? + 'jifa.heap.ref.type.outgoing' : 'jifa.heap.ref.type.incoming'), label), + newTabName, this.loadClassBounds, outbound) + newTab.loading = true + axios.get(heapDumpService(this.file, outbound ? 'classReference/outbounds/class' : 'classReference/inbounds/class'), { + params: { + objectId: id, + } + }).then((resp) => { + let topItems = []; + let record = resp.data + topItems.push( + { + rowKey: rowKey++, + label: record.label, + hasChildren: true, + objectId: record.objectId, + objectIds: record.objectIds, + objects: record.objects, + shallowHeap: record.shallowSize, + icon: outbound ? getClassRefOutboundIcon(record.type) : ICONS.objects.class, + isResult: true + } + ) + newTab.topItems = topItems + newTab.loading = false + } + ) + }, + + addClassRefsTab(title, name, load, outbound) { + this.tabIndex++; + let newTab = { + title: title, + name: name, + loading: false, + topItems: [], + load: load, + outbound: outbound, + isClassRefsTab: true + } + this.editableTabs.push(newTab) + this.editableTabsValue = name; + return newTab + }, + + pathToGCRootsOfObj(objectId, label) { + let newTabName = ++this.tabIndex + ''; + this.loadMorePathToGCRootsOfObj(this.addPathToGCRootsTab(this.buildTitle(this.$t('jifa.heap.pathToGCRoots'), label), + newTabName, objectId)) + }, + + loadMorePathToGCRootsOfObj(tab) { + tab.loading = true + axios.get(heapDumpService(this.file, 'pathToGCRoots'), { + params: { + skip: tab.count, + origin: tab.origin, + count: 10 + } + }).then((resp) => { + tab.count += resp.data.count + tab.hasMore = resp.data.hasMore + if (tab.treeData.length === 0) { + // first + tab.treeData.push(resp.data.tree) + } else { + this.mergePath(resp.data.tree.children, tab.treeData[0]) + } + tab.loading = false + }) + }, + + mergePath(children, parent) { + for (let i = 0; i < children.length; i++) { + let found = false + let child = children[i] + for (let j = 0; j < parent.children.length; j++) { + let oldChild = parent.children[j] + if (oldChild.objectId === child.objectId) { + found = true + this.mergePath(child.children, oldChild) + break; + } + } + + if (!found) { + parent.children.push(child) + } + } + }, + + addPathToGCRootsTab(title, name, objectId) { + this.tabIndex++; + let newTab = { + title: title, + name: name, + loading: false, + isPathToGCRootsTab: true, + origin: objectId, + treeData: [], + hasMore: false, + count: 0, + } + this.editableTabs.push(newTab) + this.editableTabsValue = name; + return newTab + }, + + removeTab(targetName) { + let tabs = this.editableTabs; + let activeName = this.editableTabsValue; + if (activeName === targetName) { + tabs.forEach((tab, index) => { + if (tab.name === targetName) { + let nextTab = tabs[index + 1] || tabs[index - 1]; + if (nextTab) { + activeName = nextTab.name; + } + } + }); + } + + this.editableTabsValue = activeName; + this.editableTabs = tabs.filter(tab => tab.name !== targetName); + } + }, + watch: { + editableTabs() { + if (this.editableTabs.length === 0) { + this.$emit('disableShowDynamicResultSlot') + } + } + } + } +</script> + +<style scoped> + .custom-tree-node { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 14px; + padding-right: 8px; + } +</style> + +<style> + .resultDiv { + height: 100%; + position: relative + } +</style>
diff --git a/frontend/src/components/heapdump/Fields.vue b/frontend/src/components/heapdump/Fields.vue new file mode 100644 index 0000000..8dfd98c --- /dev/null +++ b/frontend/src/components/heapdump/Fields.vue
@@ -0,0 +1,173 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <el-table + ref="fieldsTable" + v-loading="loading" + :data="tableData" + :span-method="spanMethod" + show-header + highlight-current-row + stripe + :cell-style='cellStyle' + :header-cell-style="headerCellStyle" + height="100%" + empty-text=" " + > + <el-table-column show-overflow-tooltip label="Type" width="70px"> + <template slot-scope="scope"> + <p style="font-size: 12px; margin: 0 auto;" v-if="!scope.row.isSummaryItem"> + {{scope.row.type}} + </p> + <span v-if="scope.row.isSummaryItem"> + <img :src="ICONS.misc.sumIcon" v-if="fields.length >= totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchNextPage" style="cursor: pointer" v-else/> + {{ fields.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + <el-table-column show-overflow-tooltip label="Name" width="120px" align="center"> + <template slot-scope="scope"> + <p style="font-size: 12px; margin: 0 auto;"> + {{ scope.row.name}} + </p> + </template> + </el-table-column> + + <el-table-column show-overflow-tooltip + label="Value" width="500px"> + <template slot-scope="scope"> + <p style="font-size: 12px; margin: 0 auto;"> + {{ scope.row.value}} + </p> + </template> + </el-table-column> + </el-table> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + import {ICONS} from "./IconHealper"; + + export default { + props: { + file: String, + objectId: Number, + static: {type: Boolean, default: false}, + }, + data() { + return { + ICONS, + loading: false, + fields: [], + tableData: [], + pageSize: 25, + nextPage: 0, + totalSize: 0, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + } + }, + methods: { + spanMethod({row}) { + if (row.isSummaryItem) { + return [1, 3] + } + return [1, 1] + }, + convert(fieldType) { + switch (fieldType) { + case 2 : + return 'ref' + case 4 : + return 'boolean' + case 5 : + return 'char' + case 6: + return 'float' + case 7: + return 'double' + case 8: + return 'byte' + case 9: + return 'short' + case 10: + return 'int' + case 11: + return 'long' + } + return 'unknown' + }, + fetchNextPage() { + this.fetchFields() + }, + fetchFields() { + if (!this.objectId) { + return + } + this.loading = true + let url = heapDumpService(this.file, this.static ? 'inspector/staticFields' : 'inspector/fields') + axios.get(url, { + params: { + objectId: this.objectId, + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + this.totalSize = resp.data.totalSize + if (this.totalSize > 0) { + let res = resp.data.data + res.forEach(f => { + this.fields.push({ + type: this.convert(f.fieldType), + name: f.name, + value: f.fieldType === 2 && !f.value ? 'null' : f.value + }) + } + ) + + this.tableData = this.fields.concat({ + isSummaryItem: true + }) + + this.nextPage++; + this.loading = false + } else { + this.clear() + this.loading = false + } + }) + }, + clear() { + this.fields = [] + this.tableData = [] + this.totalSize = 0 + }, + }, + watch: { + objectId(id) { + this.nextPage = 1 + this.clear() + if (id >= 0) { + this.fetchFields() + } + } + }, + mounted() { + this.nextPage = 1 + this.clear() + this.fetchFields() + } + } +</script>
diff --git a/frontend/src/components/heapdump/GCRoots.vue b/frontend/src/components/heapdump/GCRoots.vue new file mode 100644 index 0000000..69c0095 --- /dev/null +++ b/frontend/src/components/heapdump/GCRoots.vue
@@ -0,0 +1,341 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <el-table + ref="table" + :data="roots" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + :span-method="spanMethod" + row-key="rowKey" + lazy + v-loading="loading" + height="100%" + :indent=8 + :load="load" + > + + <el-table-column label="Class Name" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isRoot"> + <img :src="scope.row.icon" style="margin-right: 5px"/> + {{ scope.row.label }} + </span> + + <span v-if="scope.row.isClass" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon" style="margin-right: 5px"/> + {{ scope.row.label }} + </span> + + <span v-if="scope.row.isObject" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon" style="margin-right: 5px"/> + {{ scope.row.label }} + <!--<span style="font-weight: bold; color: #909399">--> + <!--{{ scope.row.suffix }}--> + <!--</span>--> + </span> + + <span v-if="scope.row.isOutbound" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon" style="margin-right: 5px"/> + <strong>{{ scope.row.prefix }}</strong> + {{ scope.row.label }} + <span style="font-weight: bold; color: #909399"> + {{ scope.row.suffix }} + </span> + </span> + + + <span v-if="scope.row.isClassSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchClasses(scope.row.parentRowKey, scope.row.rootTypeIndex, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" v-else/> + {{ scope.row.currentSize}} <strong> / </strong> {{scope.row.totalSize}} + </span> + + <span v-if="scope.row.isObjectSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchObjects(scope.row.parentRowKey, scope.row.rootTypeIndex, + scope.row.classIndex, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" v-else/> + {{ scope.row.currentSize}} <strong> / </strong> {{scope.row.totalSize}} + </span> + + <span v-if="scope.row.isOutboundsSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchOutbounds(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + </template> + </el-table-column> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column label="Objects" prop="objects"> + </el-table-column> + + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + + <el-table-column label="Retained Heap" prop="retainedHeap"> + </el-table-column> + </el-table> +</template> + +<script> + import axios from 'axios' + import {getIcon, getOutboundIcon, ICONS} from "./IconHealper"; + import {heapDumpService} from '../../util' + + let rowKey = 1 + export default { + props: ['file'], + data() { + return { + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + ICONS, + pageSize: 25, + loading: false, + roots: [] + } + }, + + methods: { + spanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 7] + } else if (index >= 1 && index <= 6) { + return [0, 0] + } + return [1, 1] + }, + fetchRoots() { + this.loading = true + axios.get(heapDumpService(this.file, 'GCRoots')).then(resp => { + let rootIndex = 0 + resp.data.forEach( + root => { + this.roots.push({ + rowKey: rowKey++, + isRoot: true, + rootTypeIndex: rootIndex++, + label: root.className, + objects: root.objects, + icon: ICONS.roots, + hasChildren: root.objects > 0, + }) + }, + this.loading = false + ) + }) + }, + fetchClasses(parentRowKey, rootTypeIndex, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'GCRoots/classes'), { + params: { + rootTypeIndex: rootTypeIndex, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['table'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + let classIndex = loadedLen + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + icon: ICONS.objects.class, + label: d.className, + objects: d.objects, + objectId: d.objectId, + rootTypeIndex: rootTypeIndex, + classIndex: classIndex++, + isClass: true, + hasChildren: true, + }) + }) + + loaded.push({ + rowKey: rowKey++, + parentRowKey: parentRowKey, + isClassSummary: true, + rootTypeIndex: rootTypeIndex, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + + fetchObjects(parentRowKey, rootTypeIndex, classIndex, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'GCRoots/class/objects'), { + params: { + rootTypeIndex: rootTypeIndex, + classIndex: classIndex, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['table'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + icon: getIcon(d.gCRoot, d.objectType), + label: d.label, + objectId: d.objectId, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + isObject: true, + hasChildren: true, + }) + }) + + loaded.push({ + rowKey: rowKey++, + parentRowKey: parentRowKey, + isObjectSummary: true, + rootTypeIndex: rootTypeIndex, + classIndex: classIndex, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + + fetchOutbounds(parentRowKey, objectId, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'outbounds'), { + params: { + objectId: objectId, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['table'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + icon: getOutboundIcon(d.gCRoot, d.objectType), + prefix: d.prefix, + label: d.label, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + hasChildren: d.hasOutbound, + objectId: d.objectId, + isOutbound: true + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isOutboundsSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + + load(tree, treeNode, resolve) { + if (tree.isRoot) { + this.fetchClasses(tree.rowKey, tree.rootTypeIndex, 1, resolve) + } else if (tree.isClass) { + this.fetchObjects(tree.rowKey, tree.rootTypeIndex, tree.classIndex, 1, resolve) + } else { + this.fetchOutbounds(tree.rowKey, tree.objectId, 1, resolve) + } + } + }, + + created() { + this.fetchRoots() + } + } +</script>
diff --git a/frontend/src/components/heapdump/HeapDump.vue b/frontend/src/components/heapdump/HeapDump.vue new file mode 100644 index 0000000..e0ad454 --- /dev/null +++ b/frontend/src/components/heapdump/HeapDump.vue
@@ -0,0 +1,478 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<!--suppress HtmlUnknownTag --> +<template> + <el-container style="height: 100%"> + <el-header> + <view-menu subject="analysisResult" + :file="file" :analysisState="analysisState" :type="type" :showInspector="showInspector" + @setShowInspector="setShowInspector" + @expandResultDivWidth="expandResultDivWidth" + @shrinkResultDivWidth="shrinkResultDivWidth" + @resetResultDivWidth="resetResultDivWidth"/> + </el-header> + + <el-main style="padding-top: 0; padding-bottom: 0; height: 100%"> + + <el-dialog + :title="$t('jifa.options')" + width="30%" + :visible.sync="optionViewVisible" + :close-on-press-escape=false :close-on-click-modal=false :show-close=false + append-to-body + modal> + <div> + <div> + <el-checkbox v-model="options.keepUnreachableObjects">Keep unreachable objects</el-checkbox> + </div> + </div> + + <span slot="footer" class="dialog-footer"> + <el-button @click="analyzeHeapDump" round>{{$t('jifa.confirm')}}</el-button> + </span> + </el-dialog> + + <div style="padding-top: 20px" v-if="analysisState === 'IN_PROGRESS' || analysisState === 'ERROR'"> + <b-progress height="2rem" show-progress :precision="2" + :value="progress" + :variant="progressState" + striped + :animated="progress < 100"/> + <b-card class="mt-3" bg-variant="dark" text-variant="white" v-if="message"> + <b-card-text style="white-space: pre-line;">{{message}}</b-card-text> + <div class="d-flex justify-content-center mb-3" v-if="progressState === 'info'"> + <b-spinner/> + </div> + </b-card> + </div> + + <el-container v-if="analysisState === 'SUCCESS'" style="height: 100%"> + <el-main style="padding: 5px; height: 100%"> + <el-row :gutter="5" style="height: 100%"> + <el-col :span="showInspector ? 19 : 24" style="height: 100%"> + <el-tabs class="mainTabs" v-model="activeTab" tab-position="left" :before-leave="switchTab"> + <el-tab-pane name="overview"> + <span slot="label">{{$t('jifa.heap.overview')}}</span> + <overview :file="file" + @setGenerationInfoAvailable="setGenerationInfoAvailable" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj" + @setSelectedObjectId="setSelectedObjectId" + /> + </el-tab-pane> + + <el-tab-pane name="leakSuspects" lazy> + <span slot="label">{{$t('jifa.heap.leakSuspects')}}</span> + <leak-suspects :file="file" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @setSelectedObjectId="setSelectedObjectId"/> + </el-tab-pane> + + <el-tab-pane name="GCRoots" lazy> + <span slot="label">{{$t('jifa.heap.GCRoots')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <GCRoots :file="file" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="dominatorTree" lazy> + <span slot="label"> {{$t('jifa.heap.dominatorTree')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <dominator-tree :file="file" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="histogram" lazy> + <span slot="label"> {{$t('jifa.heap.histogram')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <histogram :file="file" :generationInfoAvailable="generationInfoAvailable" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="unreachableObjects" lazy> + <span slot="label"> {{$t('jifa.heap.unreachableObjects')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <unreachable-objects :file="file" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + + <el-tab-pane name="duplicatedClasses" lazy> + <span slot="label"> {{$t('jifa.heap.duplicatedClasses')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <duplicated-classes :file="file" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="classLoaders" lazy> + <span slot="label"> {{$t('jifa.heap.classLoaders')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <class-loaders :file="file" + @setSelectedObjectId="setSelectedObjectId" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj"/> + </div> + </el-tab-pane> + + <el-tab-pane name="directByteBuffer" lazy> + <span slot="label"> {{$t('jifa.heap.directByteBuffer')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <direct-byte-buffer :file="file" + @setSelectedObjectId="setSelectedObjectId" + @pathToGCRootsOfObj="pathToGCRootsOfObj"/> + </div> + </el-tab-pane> + + <el-tab-pane name="systemProperty" lazy> + <span slot="label"> {{$t('jifa.heap.systemProperty')}}</span> + <system-property :file="file"/> + </el-tab-pane> + + <el-tab-pane name="thread" lazy> + <span slot="label"> {{$t('jifa.heap.threadInfo')}}</span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <thread :file="file" @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="OQL" lazy> + <span slot="label"> OQL </span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <OQL :file="file" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj" + @setSelectedObjectId="setSelectedObjectId"/> + </div> + </el-tab-pane> + + <el-tab-pane name="HeapFileCompare" lazy v-if="$jifa.dev()"> + <span slot="label">{{ $t("jifa.heap.compare") }}</span> + <heap-file-compare :file="file"/> + </el-tab-pane> + + <el-tab-pane name="dynamicResultSlot" :disabled="!showDynamicResultSlot" class="dynamicTab"> + <span slot="label"> <i class="el-icon-more-outline"/> </span> + <div v-bind:style="{ 'height': '100%', 'width': resultDivWidth}"> + <dynamic-result-slot ref="dynamicResultSlot" :file="file" + @disableShowDynamicResultSlot="disableShowDynamicResultSlot" + @setSelectedObjectId="setSelectedObjectId" + @outgoingRefsOfObj="outgoingRefsOfObj" + @incomingRefsOfObj="incomingRefsOfObj" + @outgoingRefsOfClass="outgoingRefsOfClass" + @incomingRefsOfClass="incomingRefsOfClass" + @pathToGCRootsOfObj="pathToGCRootsOfObj"/> + </div> + </el-tab-pane> + </el-tabs> + </el-col> + + <el-col :span="showInspector ? 5 : 0" style="height: 100%"> + <Inspector :file="file" + :objectId="selectedObjectId" + @outgoingRefsOfObj="outgoingRefsOfObj" + @setSelectedObjectId="setSelectedObjectId" + v-if="showInspector"/> + </el-col> + </el-row> + </el-main> + </el-container> + </el-main> + <el-footer> + <Footer/> + </el-footer> + </el-container> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + import Footer from "../footer" + + import Overview from './Overview' + import Inspector from './Inspector' + import LeakSuspects from './LeakSuspects' + import ViewMenu from "../menu/ViewMenu" + import SystemProperty from "./SystemProperty" + import Thread from "./Thread"; + import Histogram from "./Histogram" + import DuplicatedClasses from "./DuplicatedClasses" + import OQL from "./OQL" + import DynamicResultSlot from "./DynamicResultSlot" + import DominatorTree from "./DominatorTree" + import GCRoots from "./GCRoots" + import UnreachableObjects from './UnreachableObjects' + import ClassLoaders from './ClassLoaders' + import DirectByteBuffer from './DirectByteBuffer' + import HeapFileCompare from './HeapFileCompare' + + export default { + props: ['file'], + data() { + return { + type: 'HEAP_DUMP', + optionViewVisible: false, + options: { + keepUnreachableObjects: true, + }, + progress: 0, + progressState: 'info', + message: '', + + pollingInternal: 1000, + analysisState: 'NOT_STARTED', + + activeTab: 'overview', + oriActiveTab: null, + generationInfoAvailable: false, + selectedObjectId: null, + showDynamicResultSlot: false, + + showInspector: true, + + resultDivWidth: '100%' + } + }, + components: { + ViewMenu, + Inspector, + Overview, + LeakSuspects, + GCRoots, + DominatorTree, + DuplicatedClasses, + Histogram, + Thread, + SystemProperty, + OQL, + DynamicResultSlot, + UnreachableObjects, + ClassLoaders, + DirectByteBuffer, + HeapFileCompare, + Footer + }, + methods: { + expandResultDivWidth() { + let width = parseInt(this.resultDivWidth.substr(0, this.resultDivWidth.length - 1)); + width += 7; + this.resultDivWidth = width + "%"; + }, + + shrinkResultDivWidth() { + let width = parseInt(this.resultDivWidth.substr(0, this.resultDivWidth.length - 1)); + if (width === 100) { + return; + } + width -= 7; + this.resultDivWidth = width + "%"; + }, + + resetResultDivWidth() { + this.resultDivWidth = '100%'; + }, + + switchTab(active, old) { + if (old !== 'dynamicResultSlot') { + this.oriActiveTab = old; + } + }, + + setGenerationInfoAvailable(ava) { + this.generationInfoAvailable = ava; + }, + + setShowDynamicResultSlot(val) { + this.showDynamicResultSlot = val; + if (val) { + this.oriActiveTab = this.activeTab; + this.activeTab = 'dynamicResultSlot'; + } else if (this.activeTab === 'dynamicResultSlot') { + if (!this.oriActiveTab) { + this.oriActiveTab = 'overview'; + } + this.activeTab = this.oriActiveTab; + } + }, + + enableShowDynamicResultSlot() { + this.setShowDynamicResultSlot(true); + }, + + disableShowDynamicResultSlot() { + this.setShowDynamicResultSlot(false); + }, + + setSelectedObjectId(id) { + this.selectedObjectId = id; + }, + + setShowInspector(val) { + this.showInspector = val; + }, + + outgoingRefsOfObj(id, label) { + this.$refs['dynamicResultSlot'].outgoingRefsOfObj(id, label); + this.enableShowDynamicResultSlot(); + }, + + incomingRefsOfObj(id, label) { + this.$refs['dynamicResultSlot'].incomingRefsOfObj(id, label); + this.enableShowDynamicResultSlot(); + }, + + outgoingRefsOfClass(id, label) { + this.$refs['dynamicResultSlot'].outgoingRefsOfClass(id, label); + this.enableShowDynamicResultSlot(); + }, + + incomingRefsOfClass(id, label) { + this.$refs['dynamicResultSlot'].incomingRefsOfClass(id, label); + this.enableShowDynamicResultSlot(); + }, + + pathToGCRootsOfObj(id, label) { + this.$refs['dynamicResultSlot'].pathToGCRootsOfObj(id, label); + this.enableShowDynamicResultSlot(); + }, + + pollProgressOfAnalysis() { + let self = this; + if (!self || self._isDestroyed) { + return; + } + axios.get(heapDumpService(this.file, 'progressOfAnalysis')).then(resp => { + let state = resp.data.state; + let percent = resp.data.percent; + if (resp.data.message) { + this.message = resp.data.message.replace(/\\n/gm, "<b/>"); + } + if (state === 'IN_PROGRESS') { + if (percent >= 1) { + this.progress = 99; + } else { + this.progress = percent * 100; + } + setTimeout(this.pollProgressOfAnalysis, this.pollingInternal) + } else if (state === 'SUCCESS') { + this.progress = 100; + this.progressState = 'success'; + this.$notify({ + title: this.$t("jifa.goToOverViewPrompt"), + position: 'top-right', + type: "success", + offset: 300, + duration: 1000, + showClose: true, + onClose: () => { + this.analysisState = "SUCCESS"; + } + }) + } else { + this.progressState = 'danger'; + this.analysisState = "ERROR"; + axios.post(heapDumpService(this.file, 'release')); + } + }) + }, + + analyzeHeapDump() { + this.optionViewVisible = false; + let params = new FormData(); + params.append('keep_unreachable_objects', this.options.keepUnreachableObjects); + this.doAnalyzeHeapDump(params); + }, + + doAnalyzeHeapDump(params) { + axios.post(heapDumpService(this.file, 'analyze'), new URLSearchParams(params)).then(() => { + this.analysisState = "IN_PROGRESS"; + this.pollProgressOfAnalysis(); + }) + }, + }, + mounted() { + axios.get(heapDumpService(this.file, 'isFirstAnalysis')).then(resp => { + if (resp.data.result) { + this.optionViewVisible = true + } else { + this.doAnalyzeHeapDump(new FormData()) + } + }) + } + } +</script> + +<style scoped> + .mainTabs { + height: 100%; + } + + .mainTabs /deep/ .el-tabs__content { + height: 100%; + overflow: scroll; + } + + .mainTabs /deep/ .el-tab-pane { + height: 100%; + overflow: scroll; + } + + .mainTabs .dynamicTab /deep/ .el-tabs__content { + height: unset; + position: absolute; + top: 60px; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } + + .mainTabs .dynamicTab /deep/ .el-tab-pane { + height: unset; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } +</style>
diff --git a/frontend/src/components/heapdump/HeapFileCompare.vue b/frontend/src/components/heapdump/HeapFileCompare.vue new file mode 100644 index 0000000..f19600b --- /dev/null +++ b/frontend/src/components/heapdump/HeapFileCompare.vue
@@ -0,0 +1,230 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <div style="height: 100%; position: relative"> + <div v-if="!selectedFile" style="height: 100%"> + <div style="height: 40px; margin-bottom: 5px; margin-top: 10px;"> + <el-input style="margin-bottom: 10px;" size="mini" v-model="searchInput" + @keyup.enter.native="doSearch" + :placeholder="$t('jifa.typeKeyWord')" clearable/> + </div> + <div style="position: absolute; top: 50px; left: 0; right: 0; bottom: 80px;"> + <el-table :data="candidateFiles" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='fileViewCellStyle' + row-key="rowKey" + lazy + height="100%" + v-loading="fileViewLoading" + > + <el-table-column label="File Name ( Please double click to choose a file as a heap baseline )" prop="name" + show-overflow-tooltip> + <template slot-scope="scope"> + <span style="cursor: pointer" @dblclick="doCompare(scope.row.finalName)"> + <i class="el-icon-document"></i> {{scope.row.originalName}} + </span> + </template> + </el-table-column> + </el-table> + </div> + + <div style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px"> + <el-row type="flex" justify="space-around" style="margin-top: 15px"> + <el-col :span="8"> + <el-pagination + background + layout="prev, pager, next" + :current-page="fileViewPage" + :page-size="pageSize" + :total="candidateFileTotalSize" + @current-change="handleFileViewCurrentChange" + :hide-on-single-page=false + align="center"> + </el-pagination> + </el-col> + </el-row> + </div> + </div> + + <div v-else style="height: 100%"> + <div style="margin-bottom: 6px; height: 50px"> + <el-button size="mini" icon="el-icon-back" @click="reselect" circle></el-button> + <span style='margin-left: 10px; font-size: 15px; font-weight: normal; + font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; + color: #606266; + '> + <i class="el-icon-document"></i> {{selectedFile}} + </span> + </div> + + <div style="position: absolute; top: 50px; left: 0; right: 0; bottom: 0;"> + <el-table :data="tableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :indent=8 + height="100%" + v-loading="loading" + > + <el-table-column label="Class Name" width="800px" show-overflow-tooltip=""> + <template slot-scope="scope"> + <span v-if="scope.row.isRecord"> + <img :src="classIcon"/> {{scope.row.className}} + </span> + <span v-if="scope.row.isSummary"> + <img :src="sumIcon" v-if="records.length >= summary.totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchRecords" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{summary.totalSize}} + </span> + </template> + </el-table-column> + + <el-table-column label="Objects"> + <template slot-scope="scope"> + {{ scope.row.objects > 0 ? '+' : '' }} {{ scope.row.objects}} + </template> + </el-table-column> + + <el-table-column label="Shallow Heap"> + <template slot-scope="scope"> + {{ scope.row.shallowHeap> 0 ? '+' : '' }} {{ scope.row.shallowHeap}} + </template> + </el-table-column> + </el-table> + </div> + </div> + </div> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + + let rowKey = 1 + export default { + props: ['file'], + methods: { + fetchCompareSummary() { + this.loading = true + axios.get(heapDumpService(this.file, 'compare/summary'), { + params: { + baseline: this.selectedFile + } + }).then(resp => { + this.summary = resp.data + if (this.summary.totalSize > 0) { + this.fetchRecords() + } else { + this.loading = false + } + }) + }, + fetchRecords() { + this.loading = true + axios.get(heapDumpService(this.file, 'compare/records'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + baseline: this.selectedFile + } + }).then(resp => { + let records = resp.data.data + records.forEach(record => this.records.push({ + rowKey: rowKey++, + className: record.className, + objects: record.objects, + shallowHeap: record.shallowSize, + isRecord: true, + })) + + this.tableData = this.records.concat({ + rowKey: rowKey++, + objects: this.summary.objects, + shallowHeap: this.summary.shallowSize, + isSummary: true + }) + + this.nextPage++ + this.loading = false + }) + }, + doCompare(fileName) { + this.selectedFile = fileName + this.fetchCompareSummary() + }, + reselect() { + this.selectedFile = null + this.summary = null + this.records = [] + this.tableData = [] + this.nextPage = 1 + }, + doSearch() { + this.expectedFile = this.searchInput + this.fileViewPage = 1 + this.fetchFiles(this.fileViewPage) + }, + handleFileViewCurrentChange(page) { + this.fetchFiles(page) + }, + fetchFiles(page) { + this.fileViewLoading = true + axios.get(heapDumpService(this.file, 'compare/files'), { + params: { + page: page, + pageSize: this.pageSize, + expected: this.expectedFile, + } + }).then(resp => { + this.candidateFileTotalSize = resp.data.totalSize + this.candidateFiles = resp.data.data + this.fileViewLoading = false + }) + } + }, + data() { + return { + fileViewCellStyle: {padding: '8px', fontSize: '15px'}, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + pageSize: 25, + + fileViewPage: 1, + fileViewLoading: false, + searchInput: null, + expectedFile: null, + candidateFiles: [], + candidateFileTotalSize: 0, + + + selectedFile: null, + classIcon: require('../../assets/heap/objects/class.gif'), + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + loading: false, + summary: null, + nextPage: 1, + records: [], + tableData: [], + } + }, + created() { + this.fetchFiles(this.fileViewPage) + } + } +</script>
diff --git a/frontend/src/components/heapdump/Histogram.vue b/frontend/src/components/heapdump/Histogram.vue new file mode 100644 index 0000000..da9a607 --- /dev/null +++ b/frontend/src/components/heapdump/Histogram.vue
@@ -0,0 +1,207 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div style="height: 100%"> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-item divider/> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <el-table :data="tableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :span-method="spanMethod" + height="100%" + :indent=8 + v-loading="loading" + > + <el-table-column :label="label"> + <template slot-scope="scope"> + <span v-if="scope.row.isRecord" @click="$emit('setSelectedObjectId', scope.row.objectId)" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu + style="cursor: pointer"> + <img :src="scope.row.icon"/> {{scope.row.label}} + </span> + + <span v-if="scope.row.isSummary"> + <img :src="sumIcon" v-if="records.length >= totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchHistogram" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + + + <el-table-column v-if="generationInfoAvailable"/> + <el-table-column v-if="generationInfoAvailable"/> + <el-table-column v-if="generationInfoAvailable"/> + + <el-table-column v-if="!generationInfoAvailable"/> + <el-table-column v-if="!generationInfoAvailable"/> + <el-table-column v-if="!generationInfoAvailable"/> + <el-table-column v-if="!generationInfoAvailable"/> + <el-table-column v-if="!generationInfoAvailable"/> + + <el-table-column label="Objects" prop="numberOfObjects"> + </el-table-column> + + <el-table-column label="Shallow Heap" prop="shallowSize"> + </el-table-column> + + <el-table-column label="Objects(Y)" prop="numberOfYoungObjects" v-if="generationInfoAvailable"> + </el-table-column> + + <el-table-column label="Shallow Heap(Y) " prop="shallowSizeOfYoung" v-if="generationInfoAvailable"> + </el-table-column> + + <el-table-column label="Objects(O)" prop="numberOfOldObjects" v-if="generationInfoAvailable"> + </el-table-column> + + <el-table-column label="Shallow Heap(O)" prop="shallowSizeOfOld" v-if="generationInfoAvailable"> + </el-table-column> + + <el-table-column label="Retained Heap"> + <template slot-scope="scope"> + <span v-if="scope.row.retainedSize < 0"> + >= {{ -scope.row.retainedSize }} + </span> + + <span v-else> + {{ scope.row.retainedSize }} + </span> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> + + import axios from 'axios' + import {heapDumpService} from '../../util' + + let rowKey = 1 + export default { + props: ['file', 'generationInfoAvailable'], + methods: { + spanMethod(row) { + let index = row.columnIndex + if (this.generationInfoAvailable) { + if (index === 0) { + return [1, 4] + } else if (index >= 1 && index <= 3) { + return [0, 0] + } + return [1, 1] + } else { + if (index === 0) { + return [1, 6] + } else if (index >= 1 && index <= 5) { + return [0, 0] + } + return [1, 1] + } + }, + fetchHistogram() { + this.loading = true + axios.get(heapDumpService(this.file, 'histogram'), { + params: { + groupingBy: this.groupingBy, + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + let records = resp.data.data + this.totalSize = resp.data.totalSize + records.forEach(record => + this.records.push({ + rowKey: rowKey++, + objectId: record.objectId, + label: record.label, + icon: this.classIcon, + numberOfObjects: record.numberOfObjects, + shallowSize: record.shallowSize, + + numberOfYoungObjects: record.numberOfYoungObjects, + shallowSizeOfYoung: record.shallowSizeOfYoung, + + numberOfOldObjects: record.numberOfOldObjects, + shallowSizeOfOld: record.shallowSizeOfOld, + + retainedSize: record.retainedSize, + isRecord: true + })) + + this.tableData = this.records.concat({ + rowKey: rowKey++, + isSummary: true + }) + this.nextPage++ + this.loading = false + }) + }, + }, + data() { + return { + loading: false, + classIcon: require('../../assets/heap/objects/class.gif'), + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + label: 'Class Name', + groupingBy: 'by_class', + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + + records: [], + tableData: [], + nextPage: 1, + pageSize: 25, + totalSize: 0, + + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + } + }, + created() { + this.fetchHistogram() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/IconHealper.js b/frontend/src/components/heapdump/IconHealper.js new file mode 100644 index 0000000..3e1f988 --- /dev/null +++ b/frontend/src/components/heapdump/IconHealper.js
@@ -0,0 +1,152 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +export const ICONS = { + id: require('../../assets/heap/id.gif'), + size: require('../../assets/heap/size.gif'), + roots: require('../../assets/heap/roots.gif'), + misc: { + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + }, + decorations: { + gc_root: require('../../assets/heap/decorations/gc_root.gif') + }, + objects: { + class_obj: require('../../assets/heap/objects/class_obj.gif'), + class_obj_gc_root: require('../../assets/heap/objects/class_obj_gc_root.gif'), + classloader_obj: require('../../assets/heap/objects/classloader_obj.gif'), + classloader_obj_gc_root: require('../../assets/heap/objects/classloader_obj_gc_root.gif'), + array_obj: require('../../assets/heap/objects/array_obj.gif'), + array_obj_gc_root: require('../../assets/heap/objects/array_obj_gc_root.gif'), + instance_obj: require('../../assets/heap/objects/instance_obj.gif'), + instance_obj_gc_root: require('../../assets/heap/objects/instance_obj_gc_root.gif'), + class_package: require('../../assets/heap/objects/package.gif'), + superclass: require('../../assets/heap/objects/superclass.gif'), + class: require('../../assets/heap/objects/class.gif'), + + out: { + class_obj: require('../../assets/heap/objects/out/class_obj.gif'), + class: require('../../assets/heap/objects/out/class.gif'), + class_mixed: require('../../assets/heap/objects/out/class_mixed.gif'), + class_old: require('../../assets/heap/objects/out/class_out_old.gif'), + class_obj_gc_root: require('../../assets/heap/objects/out/class_obj_gc_root.gif'), + classloader_obj: require('../../assets/heap/objects/out/classloader_obj.gif'), + classloader_obj_gc_root: require('../../assets/heap/objects/out/classloader_obj_gc_root.gif'), + array_obj: require('../../assets/heap/objects/out/array_obj.gif'), + array_obj_gc_root: require('../../assets/heap/objects/out/array_obj_gc_root.gif'), + instance_obj: require('../../assets/heap/objects/out/instance_obj.gif'), + instance_obj_gc_root: require('../../assets/heap/objects/out/instance_obj_gc_root.gif'), + }, + + in: { + class_obj: require('../../assets/heap/objects/in/class_obj.gif'), + class: require('../../assets/heap/objects/in/class.gif'), + class_mixed: require('../../assets/heap/objects/in/class_mixed.gif'), + class_old: require('../../assets/heap/objects/in/class_in_old.gif'), + class_obj_gc_root: require('../../assets/heap/objects/in/class_obj_gc_root.gif'), + classloader_obj: require('../../assets/heap/objects/in/classloader_obj.gif'), + classloader_obj_gc_root: require('../../assets/heap/objects/in/classloader_obj_gc_root.gif'), + array_obj: require('../../assets/heap/objects/in/array_obj.gif'), + array_obj_gc_root: require('../../assets/heap/objects/in/array_obj_gc_root.gif'), + instance_obj: require('../../assets/heap/objects/in/instance_obj.gif'), + instance_obj_gc_root: require('../../assets/heap/objects/in/instance_obj_gc_root.gif'), + }, + } +} + +import {CLASS_TYPE, OBJECT_TYPE} from "./CommonType"; + +export function getIcon(isGCRoot, objType) { + + if (objType === OBJECT_TYPE.CLASS) { + return isGCRoot ? ICONS.objects.class_obj_gc_root : ICONS.objects.class_obj; + } + + if (objType === OBJECT_TYPE.CLASSLOADER) { + return isGCRoot ? ICONS.objects.classloader_obj_gc_root : ICONS.objects.classloader_obj; + } + + if (objType === OBJECT_TYPE.ARRAY) { + return isGCRoot ? ICONS.objects.array_obj_gc_root : ICONS.objects.array_obj; + } + + if (objType === OBJECT_TYPE.NORMAL) { + return isGCRoot ? ICONS.objects.instance_obj_gc_root : ICONS.objects.instance_obj; + } +} + +export function getOutboundIcon(isGCRoot, objType) { + + if (objType === OBJECT_TYPE.CLASS) { + return isGCRoot ? ICONS.objects.out.class_obj_gc_root : ICONS.objects.out.class_obj; + } + + if (objType === OBJECT_TYPE.CLASSLOADER) { + return isGCRoot ? ICONS.objects.out.classloader_obj_gc_root : ICONS.objects.out.classloader_obj; + } + + if (objType === OBJECT_TYPE.ARRAY) { + return isGCRoot ? ICONS.objects.out.array_obj_gc_root : ICONS.objects.out.array_obj; + } + + if (objType === OBJECT_TYPE.NORMAL) { + return isGCRoot ? ICONS.objects.out.instance_obj_gc_root : ICONS.objects.out.instance_obj; + } +} + +export function getInboundIcon(isGCRoot, objType) { + + if (objType === OBJECT_TYPE.CLASS) { + return isGCRoot ? ICONS.objects.in.class_obj_gc_root : ICONS.objects.in.class_obj; + } + + if (objType === OBJECT_TYPE.CLASSLOADER) { + return isGCRoot ? ICONS.objects.in.classloader_obj_gc_root : ICONS.objects.in.classloader_obj; + } + + if (objType === OBJECT_TYPE.ARRAY) { + return isGCRoot ? ICONS.objects.in.array_obj_gc_root : ICONS.objects.in.array_obj; + } + + if (objType === OBJECT_TYPE.NORMAL) { + return isGCRoot ? ICONS.objects.in.instance_obj_gc_root : ICONS.objects.in.instance_obj; + } +} + +export function getClassRefInboundIcon(type) { + if (type === CLASS_TYPE.NEW) { + return ICONS.objects.in.class + } + + if (type === CLASS_TYPE.MIXED) { + return ICONS.objects.in.class_mixed + + } + if (type === CLASS_TYPE.OLD_FAD) { + return ICONS.objects.in.class_old + } +} + +export function getClassRefOutboundIcon(type) { + if (type === CLASS_TYPE.NEW) { + return ICONS.objects.out.class + } + + if (type === CLASS_TYPE.MIXED) { + return ICONS.objects.out.class_mixed + + } + if (type === CLASS_TYPE.OLD_FAD) { + return ICONS.objects.out.class_old + } +} \ No newline at end of file
diff --git a/frontend/src/components/heapdump/Inspector.vue b/frontend/src/components/heapdump/Inspector.vue new file mode 100644 index 0000000..ddc4ac2 --- /dev/null +++ b/frontend/src/components/heapdump/Inspector.vue
@@ -0,0 +1,276 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-clipboard="http://www.w3.org/1999/xhtml"> + <el-container style="height: 100%"> + <el-main style="padding: 0; height: 100%"> + <div style="height: 100%; position: relative;"> + <el-tabs class="firstTabs" value="inspectorObjectView" style="position:relative; height: 38%;"> + <el-tab-pane name="inspectorObjectView"> + <span slot="label"> + <i class="el-icon-search"/> + <span style="margin-left: 2px"> Inspector</span> + </span> + + <div style="margin-bottom: 5px"> + <el-input size="mini" + width="60%" + placeholder="Object Address" + class="input-with-select" + v-model="objectAddress" + @keyup.enter.native="searchByAddress" + clearable> + <el-button slot="append" :icon="searching ? 'el-icon-loading' : 'el-icon-search'" + :disabled="searching" + @click="searchByAddress"/> + </el-input> + </div> + + + <el-table v-loading="viewLoading" + :data="objectOverview" + :show-header="false" + :highlight-current-row="true" + stripe + :cell-style="cellStyle" + empty-text=" " + height="80%" + > + <el-table-column align="left" show-overflow-tooltip> + <template slot-scope="scope"> + <p style="font-size: 12px; margin: 0 auto;"> + <img :src="scope.row.icon"/> {{ scope.row.data}} + <span style="font-weight: bold; color: #909399" + v-if="scope.row.suffix">{{ " " + scope.row.suffix}}</span> + <i v-if="scope.row.copyable" class="el-icon-document-copy copy-icon" + style="padding-left: 5px" + v-clipboard:copy="scope.row.data"/> + </p> + </template> + </el-table-column> + </el-table> + </el-tab-pane> + </el-tabs> + + <el-tabs :value="activeName" + class="bottomTabs" style="position: absolute; top: 38%; left: 0; right: 0; bottom: 0;"> + <el-tab-pane label="Attributes" name="Attributes"> + <Fields :file="file" :object-id="objectId"/> + </el-tab-pane> + <el-tab-pane label="Statics" name="Statics"> + <div style="height: 100%"> + <Fields :file="file" :object-id="objectId" static/> + </div> + </el-tab-pane> + <!-- <el-tab-pane label="Class Hierarchy" name="Class Hierarchy" disabled>--> + <!-- </el-tab-pane>--> + <el-tab-pane label="Value" name="Value"> + <div v-loading="valueLoading"> + <el-input + v-model="objectValue" + type="textarea" + style="font-size: 12px" + readonly + autosize> + </el-input> + </div> + </el-tab-pane> + </el-tabs> + </div> + </el-main> + </el-container> +</template> +<script> + + import axios from 'axios' + import {heapDumpService} from '../../util' + import {getIcon, ICONS} from './IconHealper'; + import {OBJECT_TYPE} from './CommonType'; + import Fields from './Fields' + + export default { + components: {Fields}, + props: ['file', 'objectId'], + data() { + return { + objectOverview: [], + activeName: 'Attributes', + cellStyle: {padding: 0}, + objectValue: '', + objectAddress: '', + searching: false, + viewLoading: false, + valueLoading: false, + } + }, + methods: { + locationDesc(locationType) { + if (locationType === 1) { + return "Young" + } + + if (locationType === 2) { + return "Old" + } + return "" + }, + searchByAddress() { + if (this.objectAddress) { + this.searching = true + let address = this.objectAddress + if (address.startsWith('0x') || address.startsWith('0X')) { + address = address.substring(2) + } + address = parseInt(address, 16); + axios.get(heapDumpService(this.file, "inspector/addressToId"), { + params: { + objectAddress: address + } + }).then(resp => { + this.$emit('setSelectedObjectId', resp.data) + this.$emit('outgoingRefsOfObj', resp.data, this.objectAddress) + this.searching = false + }).catch(() => { + this.objectAddress = null + this.searching = false + }) + } + }, + inspect() { + if (!this.objectId) { + return + } + + this.viewLoading = true + axios.get(heapDumpService(this.file, "inspector/objectView"), { + params: { + objectId: this.objectId + } + }).then(resp => { + let ov = resp.data + + let oa = '0x' + ov.objectAddress.toString(16) + + let tmpView = [] + tmpView.push({data: oa, icon: ICONS.id, suffix: this.locationDesc(ov.locationType), copyable: true}) + let name = ov.name + let p = '' + let dotPos = name.lastIndexOf(".") + if (dotPos >= 0) { + p = name.substring(0, dotPos) + name = name.substring(dotPos + 1) + } + tmpView.push({data: name, icon: getIcon(ov.gCRoot, ov.objectType)}) + tmpView.push({data: p, icon: ICONS.objects.class_package}) + + tmpView.push({ + data: ov.classLabel, + icon: getIcon(ov.classGCRoot, OBJECT_TYPE.CLASS) + }) + + tmpView.push({data: ov.superClassName ? ov.superClassName : ' ', icon: ICONS.objects.superclass}) + + tmpView.push({ + data: ov.classLoaderLabel, + icon: getIcon(ov.classLoaderGCRoot, OBJECT_TYPE.CLASSLOADER) + }) + tmpView.push({data: ov.shallowSize + ' (shallow size)', icon: ICONS.size}) + tmpView.push({data: ov.retainedSize + ' (retained size)', icon: ICONS.size}) + tmpView.push({data: ov.gcRootInfo, icon: ICONS.decorations.gc_root}) + this.objectOverview = tmpView + let maxContent = '' + tmpView.forEach(v => { + if (v.data.length > maxContent.length) { + maxContent = v.data + } + }) + if (ov.objectType === OBJECT_TYPE.CLASS) { + this.activeName = 'Statics' + } else { + this.activeName = 'Attributes' + } + this.viewLoading = false + }).catch(() => { + this.objectOverview = [] + this.viewLoading = false + }) + + this.valueLoading = true + axios.get(heapDumpService(this.file, "inspector/value"), { + params: { + objectId: this.objectId + } + }).then(resp => { + this.objectValue = resp.data + this.valueLoading = false + }).catch(() => { + this.valueLoading = false + }) + }, + }, + watch: { + objectId(id) { + if (id >= 0) { + this.inspect() + } else { + this.objectOverview = [] + } + }, + }, + mounted() { + this.inspect() + } + } +</script> + +<style scoped> + .copy-icon:hover { + color: #409EFF; + cursor: pointer; + } + + .firstTabs /deep/ .el-tabs__content { + position: absolute; + top: 45px; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } + + .firstTabs /deep/ .el-tab-pane { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } + + .bottomTabs /deep/ .el-tabs__content { + position: absolute; + top: 45px; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } + + .bottomTabs /deep/ .el-tab-pane { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: scroll; + } +</style> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/LeakSuspects.vue b/frontend/src/components/heapdump/LeakSuspects.vue new file mode 100644 index 0000000..a5d01e5 --- /dev/null +++ b/frontend/src/components/heapdump/LeakSuspects.vue
@@ -0,0 +1,165 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <div style="height: 100%; position: relative"> + <el-collapse v-if="useful" v-model="activeNames" style="width: 100%"> + <el-collapse-item v-loading="loading" :title='$t("jifa.heap.overview")' name="0"> + <div style="position: relative;"> + <div style="position: absolute; top: 30px; left: 30px;" v-html="descOfSelectedSlice"></div> + <div> + <doughnut-chart :chart-data="chartData" :options="chartOptions"></doughnut-chart> + </div> + </div> + </el-collapse-item> + <el-collapse-item v-for="(record) in records" v-bind:key="record.name" :title="record.name" :name="record.name"> + <el-tabs tab-position="left"> + <el-tab-pane :label="$t('jifa.heap.description')"> + <div v-html="record.desc"></div> + </el-tab-pane> + <el-tab-pane v-if="record.paths" :label="$t('jifa.heap.detail')"> + <el-tree + :data="record.paths" + node-key="objectId" + > + <span class="custom-tree-node" style="font-size: 12px" slot-scope="{ node, data }" + @click="$emit('setSelectedObjectId', data.objectId)"> + <span> + <img :src="getIcon(data.gCRoot, data.objectType)" style="margin-right: 5px"/> + {{ data.label }} + </span> + <span> + {{ data.shallowSize }} / {{ data.retainedSize }} + </span> + </span> + + </el-tree> + </el-tab-pane> + </el-tabs> + </el-collapse-item> + </el-collapse> + </div> +</template> + +<script> + import axios from 'axios' + import DoughnutChart from '../charts/DoughnutChart' + import {heapDumpService} from '../../util' + import {a2rgb, PIE_COLORS, REMAINDER_COLOR} from "./ColorHelper"; + import {getIcon} from "./IconHealper" + + export default { + props: ['file'], + components: { + DoughnutChart + }, + methods: { + getIcon, + clickPie(event, elements) { + if (elements.length > 0) { + let index = elements[0]._index + this.descOfSelectedSlice = this.slices[index].desc + this.$emit("setSelectedObjectId", this.slices[index].objectId) + } else { + this.descOfSelectedSlice = null + } + }, + fetchReport() { + this.loading = true + axios.get(heapDumpService(this.file, 'leak/report')).then(resp => { + this.useful = resp.data.useful + if (this.useful) { + this.slices = resp.data.slices + let labels = [] + let data = [] + for (let i = 0; i < this.slices.length; i++) { + labels.push(this.slices[i].label) + data.push(this.slices[i].value) + } + + let color = [] + let len = this.slices.length + for (let i = 0; i < len - 1; i++) { + color.push(a2rgb(PIE_COLORS[i % PIE_COLORS.length])) + } + if (this.slices[len - 1].objectId === -1 + || this.slices[len - 1].label === 'Remainder') { + color.push(a2rgb(REMAINDER_COLOR)) + } else { + color.push(a2rgb((len - 1) % PIE_COLORS.length)) + } + + this.chartData = { + labels: labels, + datasets: [ + { + backgroundColor: color, + data: data, + } + ] + } + + this.records = resp.data.records + this.records.forEach( + r => { + this.activeNames.push(r.name) + } + ) + } + this.loading = false + }) + } + + }, + data() { + return { + activeNames: ['0'], + loading: false, + + chartData: {}, + chartOptions: { + legend: false, + responsive: true, + maintainAspectRatio: false, + pieceLabel: { + mode: 'percentage', + precision: 1 + }, + animation: { + // animateScale: true, + // easing: 'linear' + }, + onClick: this.clickPie + }, + + useful: true, + slices: null, + descOfSelectedSlice: null, + records: null, + } + }, + created() { + this.fetchReport() + } + } +</script> + +<style scoped> + .custom-tree-node { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 14px; + padding-right: 8px; + } +</style> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/OQL.vue b/frontend/src/components/heapdump/OQL.vue new file mode 100644 index 0000000..54642b5 --- /dev/null +++ b/frontend/src/components/heapdump/OQL.vue
@@ -0,0 +1,378 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div style="height: 100%; position: relative"> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + <v-contextmenu-item divider></v-contextmenu-item> + <v-contextmenu-item + @click="$emit('pathToGCRootsOfObj', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <div style="height: 45px; margin-top: 5px"> + <el-autocomplete + v-model="oql" + :fetch-suggestions="queryHistory" + placeholder="Object Query Language ..." + :trigger-on-focus="false" + prefix-icon="el-icon-edit" + @keyup.enter.native="search" + clearable + style="display: flex" + > + <template slot="append"> + <el-button :icon="searching ? 'el-icon-loading':'el-icon-search'" :disabled="searching" @click="search"> + </el-button> + </template> + </el-autocomplete> + </div> + + <div align="left" style="height: 25px; margin-bottom: 5px"> + <a href="https://help.eclipse.org/oxygen/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Freference%2Foqlsyntax.html&cp=66_4_2" + target="_blank" style="font-size: 12px; font-weight: bold; color: #909399"> + OQL Help + </a> + </div> + + <div v-loading="loading" style="position: absolute; top: 80px; left: 0; right: 0; bottom: 0;"> + <el-table v-if="isTreeResult" + ref='treeResultTable' :data="treeTableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :indent=8 + height="100%" + :load="loadOutbounds"> + <el-table-column label="Class Name" width="800px" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isResult" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.label" + v-contextmenu:contextmenu> + <img :src="scope.row.icon" style="margin-right: 5px"/> + <strong>{{ scope.row.prefix }}</strong> + {{ scope.row.label }} + <span style="font-weight: bold; color: #909399"> + {{ scope.row.suffix }} + </span> + </span> + + <span v-if="scope.row.isOutboundsSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchOutbounds(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + + <span v-if="scope.row.isSummaryItem"> + <img :src="ICONS.misc.sumIcon" v-if="treeResult.length >= totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchResult(scope.row.oql)" style="cursor: pointer" v-else/> + {{ treeResult.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + <el-table-column label="Retained Heap" prop="retainedHeap"> + </el-table-column> + </el-table> + + <el-table v-if="isTableResult" + ref='tableResultTable' :data="tableTableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :indent=8 + height="100%"> + + <el-table-column v-for="(column, index) in tableResultColumns" :label="column" v-bind:key="column"> + <template slot-scope="scope"> + <span v-if="scope.row.isResult" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer" + @contextmenu="contextMenuTargetObjectId = scope.row.objectId; contextMenuTargetObjectLabel = scope.row.values[index] ? scope.row.values[index] : 'null'" + v-contextmenu:contextmenu> + {{ scope.row.values[index] ? scope.row.values[index] : 'null' }} + </span> + + <span v-if="scope.row.isSummaryItem && index === 0"> + <img :src="ICONS.misc.sumIcon" v-if="tableResult.length >= totalSize"/> + <img :src="ICONS.misc.sumPlusIcon" @dblclick="fetchResult(scope.row.oql)" style="cursor: pointer" v-else/> + {{ tableResult.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + </el-table> + + + <el-input v-if="isTextResult" + v-model="textResult" + type="textarea" + readonly + autosize> + </el-input> + </div> + </div> +</template> + +<script> + import axios from 'axios' + import {getOutboundIcon, ICONS} from "./IconHealper"; + import {heapDumpService} from "../../util"; + + let rowKey = 1 + + // oql result type + const TREE = 1 + const TABLE = 2 + const TEXT = 3 + + export default { + props: ['file'], + data() { + return { + ICONS, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + searching: false, + loading: false, + oql: '', + nextPage: 1, + pageSize: 25, + totalSize: 0, + resultType: 0, + + contextMenuTargetObjectId: null, + contextMenuTargetObjectLabel: null, + + treeResult: [], + treeTableData: [], + + tableResult: [], + tableResultColumns: [], + tableTableData: [], + + textResult: '', + + isTreeResult: false, + isTableResult: false, + isTextResult: false, + + historyOQLs: [] + } + }, + methods: { + adjustDataByResultType(type) { + this.isTreeResult = type === TREE + this.isTableResult = type === TABLE + this.isTextResult = type === TEXT + }, + fetchResult(oql) { + if (!oql || oql.length === 0) { + return + } + this.loading = true + axios.get(heapDumpService(this.file, 'oql'), { + params: { + oql: oql, + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + this.adjustDataByResultType(resp.data.type) + if (this.isTreeResult) { + this.putHistory(oql) + this.totalSize = resp.data.pv.totalSize + let data = resp.data.pv.data + data.forEach(d => { + this.treeResult.push({ + rowKey: rowKey++, + icon: getOutboundIcon(d.gCRoot, d.objectType), + prefix: d.prefix, + label: d.label, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + hasChildren: d.hasOutbound, + objectId: d.objectId, + isResult: true + }) + }) + this.treeTableData = this.treeResult.concat({ + rowKey: rowKey++, + oql: oql, + isSummaryItem: true + }) + this.nextPage++ + } else if (this.isTableResult) { + this.putHistory(oql) + this.totalSize = resp.data.pv.totalSize + this.tableResultColumns = resp.data.columns + let data = resp.data.pv.data + data.forEach(d => { + this.tableResult.push({ + rowKey: rowKey++, + objectId: d.objectId, + values: d.values, + hasChildren: false, + isResult: true + }) + }) + this.tableTableData = this.tableResult.concat({ + rowKey: rowKey++, + oql: oql, + isSummaryItem: true + }) + this.nextPage++ + } else if (this.isTextResult) { + this.textResult = resp.data.text + } + this.searching = false + this.loading = false + }) + }, + loadOutbounds(tree, treeNode, resolve) { + this.fetchOutbounds(tree.rowKey, tree.objectId, 1, resolve) + }, + fetchOutbounds(parentRowKey, objectId, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'outbounds'), { + params: { + objectId: objectId, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['treeResultTable'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + + let res = resp.data.data + res.forEach(d => { + loaded.push({ + rowKey: rowKey++, + icon: getOutboundIcon(d.gCRoot, d.objectType), + prefix: d.prefix, + label: d.label, + suffix: d.suffix, + shallowHeap: d.shallowSize, + retainedHeap: d.retainedSize, + hasChildren: d.hasOutbound, + objectId: d.objectId, + isResult: true + }) + }) + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isOutboundsSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + }, + clear() { + this.nextPage = 1 + this.totalSize = 0 + + this.treeResult = [] + this.treeTableData = [] + + this.tableResult = [] + this.tableResultColumns = [] + this.tableTableData = [] + this.textResult = '' + }, + + search() { + if (this.oql) { + this.searching = true + this.clear() + this.fetchResult(this.oql) + } + }, + + putHistory(oql) { + let target = oql.trim() + for (let i = 0; i < this.historyOQLs.length; i++) { + if (this.historyOQLs[i].value === target) { + return + } + } + + this.historyOQLs.push({value: target}) + if (this.historyOQLs.length > 11) { + this.historyOQLs.shift() + } + }, + + queryHistory(queryString, cb) { + let history = this.historyOQLs; + let results = queryString ? history.filter(this.createFilter(queryString)) : history; + cb(results); + }, + + createFilter(queryString) { + return (history) => { + return (history.value.toLowerCase().indexOf(queryString.toLowerCase().trim()) === 0); + }; + }, + } + } +</script>
diff --git a/frontend/src/components/heapdump/Overview.vue b/frontend/src/components/heapdump/Overview.vue new file mode 100644 index 0000000..45c9012 --- /dev/null +++ b/frontend/src/components/heapdump/Overview.vue
@@ -0,0 +1,210 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-contextmenu="http://www.w3.org/1999/xhtml"> + <div> + <v-contextmenu ref="contextmenu"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.object.label')" + v-if="selectedBigObject && selectedBigObject.objectId >=0"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfObj', selectedBigObject.objectId, selectedBigObject.label)"> + {{$t('jifa.heap.ref.object.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfObj', selectedBigObject.objectId, selectedBigObject.label)"> + {{$t('jifa.heap.ref.object.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')" + v-if="this.selectedBigObject && this.selectedBigObject.objectId >=0"> + <v-contextmenu-submenu :title="$t('jifa.heap.ref.type.label')"> + <v-contextmenu-item + @click="$emit('outgoingRefsOfClass', contextMenuTargetObjectId, contextMenuTargetObjectLabel)"> + {{$t('jifa.heap.ref.type.outgoing')}} + </v-contextmenu-item> + <v-contextmenu-item + @click="$emit('incomingRefsOfClass', selectedBigObject.objectId, selectedBigObject.label())"> + {{$t('jifa.heap.ref.type.incoming')}} + </v-contextmenu-item> + </v-contextmenu-submenu> + </v-contextmenu-submenu> + + <v-contextmenu-item divider v-if="selectedBigObject && selectedBigObject.objectId >=0"></v-contextmenu-item> + + <v-contextmenu-item + v-if="selectedBigObject && selectedBigObject.objectId >=0" + @click="$emit('pathToGCRootsOfObj', selectedBigObject.objectId, selectedBigObject.label)"> + {{$t('jifa.heap.pathToGCRoots')}} + </v-contextmenu-item> + </v-contextmenu> + + <el-collapse v-model="activeNames" style="width: 100%;"> + <el-collapse-item v-loading="loading" :title="$t('jifa.heap.basicInformation')" name="1"> + <el-table v-loading="loading" + :data="details" + :show-header="false" + :highlight-current-row="false" + stripe + :cell-style='cellStyle' + height="280px" + > + <el-table-column prop="key" width="300px"> + </el-table-column> + <el-table-column prop="value"> + </el-table-column> + </el-table> + </el-collapse-item> + + <el-collapse-item v-loading="loading" title='Biggest Objects by Retained Size' name="2"> + <doughnut-chart :chart-data="chartData" :options="chartOptions" v-contextmenu:contextmenu></doughnut-chart> + <p style='margin-top: 20px; margin-bottom: -20px; font-size: 13px; font-weight: 500; color: #606266;'> + {{selectedBigObject ? buildSelectedBigObjectInfo() : $t("jifa.heap.usedHeapSize") + ': ' + +toSizeString(totalSize)}} + </p> + </el-collapse-item> + </el-collapse> + </div> +</template> +<script> + import DoughnutChart from '../charts/DoughnutChart' + import axios from 'axios' + import {heapDumpService, toCountString, toSizeString} from '../../util' + import {formatDate} from 'element-ui/src/utils/date-util' + import {a2rgb, PIE_COLORS, REMAINDER_COLOR} from "./ColorHelper"; + + export default { + props: ['file'], + components: { + DoughnutChart + }, + methods: { + toSizeString, + selectBigObject(event, elements) { + if (elements.length > 0) { + let index = elements[0]._index + this.selectedBigObject = this.bigObjects[index] + this.$emit("setSelectedObjectId", this.selectedBigObject.objectId) + } else { + this.selectedBigObject = null + } + }, + buildSelectedBigObjectInfo() { + let obj = this.selectedBigObject + return obj.label + ' [' + toSizeString(obj.value) + ', ' + + ((obj.value) / this.totalSize * 100).toPrecision(3) + '%]' + } + }, + data() { + return { + loading: false, + activeNames: ['1', '2'], + details: null, + totalSize: 0, + selectedBigObject: null, + cellStyle: {padding: '8px'}, + + bigObjects: [], + chartData: {}, + chartOptions: { + legend: false, + responsive: true, + maintainAspectRatio: false, + pieceLabel: { + mode: 'percentage', + precision: 1 + }, + animation: { + // animateScale: true, + // easing: 'linear' + }, + onClick: this.selectBigObject + } + }; + }, + created() { + this.loading = true + + axios.get(heapDumpService(this.file, 'details')).then(resp => { + + this.$emit("setGenerationInfoAvailable", resp.data.generationInfoAvailable) + + this.totalSize = resp.data.usedHeapSize + this.details = [ + { + key: this.$t("jifa.heap.usedHeapSize"), + value: toSizeString(resp.data.usedHeapSize) + }, + { + key: this.$t("jifa.heap.numberOfClasses"), + value: toCountString(resp.data.numberOfClasses) + }, + { + key: this.$t("jifa.heap.numberOfObjects"), + value: toCountString(resp.data.numberOfObjects) + }, + { + key: this.$t("jifa.heap.numberOfClassLoaders"), + value: toCountString(resp.data.numberOfClassLoaders) + }, + { + key: this.$t("jifa.heap.numberOfGCRoots"), + value: toCountString(resp.data.numberOfGCRoots) + }, + { + key: this.$t("jifa.heap.heapCreationDate"), + value: formatDate(new Date(resp.data.creationDate), 'yyyy-MM-dd HH:mm:ss') + }, + { + key: this.$t("jifa.heap.OSBit"), + value: resp.data.identifierSize === 8 ? '64 bit' : '32 bit' + }, + ] + + axios.get(heapDumpService(this.file, 'biggestObjects')).then(resp => { + this.bigObjects = resp.data; + let labels = [] + let data = [] + for (let i = 0; i < resp.data.length; i++) { + labels.push(this.bigObjects[i].label) + data.push(this.bigObjects[i].value) + } + + let color = [] + for (let i = 0; i < resp.data.length - 1; i++) { + color.push(a2rgb(PIE_COLORS[i % PIE_COLORS.length])) + } + + if (this.bigObjects[this.bigObjects.length - 1].objectId === -1 + || this.bigObjects[this.bigObjects.length - 1].label === 'Remainder') { + color.push(a2rgb(REMAINDER_COLOR)) + } else { + color.push(a2rgb((this.bigObjects.length - 1) % PIE_COLORS.length)) + } + + this.chartData = { + labels: labels, + datasets: [ + { + backgroundColor: color, + data: data, + } + ] + } + this.loading = false + }).catch(() => { + this.chartData = {} + }) + }) + } + }; +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/SystemProperty.vue b/frontend/src/components/heapdump/SystemProperty.vue new file mode 100644 index 0000000..4ed3e08 --- /dev/null +++ b/frontend/src/components/heapdump/SystemProperty.vue
@@ -0,0 +1,83 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <el-table :data="systemProperties.filter(data => !keyword || data.key.toLowerCase().includes(keyword.toLowerCase()) + || data.value.toLowerCase().includes(keyword.toLowerCase()))" + :highlight-current-row="false" + height="100%" + stripe + v-loading="loading" + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + :span-method="tableSpanMethod"> + <el-table-column label="Key" prop="key" width="400px"> + </el-table-column> + <el-table-column label="Value" prop="value"> + </el-table-column> + <el-table-column align="right"> + <template slot="header" slot-scope="scope"> + <el-input size="mini" v-model="keyword" style="width: 50%;" + :placeholder="$t('jifa.typeKeyWord')" clearable/> + </template> + </el-table-column> + </el-table> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + + export default { + props: ['file'], + methods: { + fetchSystemProperty() { + if (this.systemProperties.length > 0) { + return + } + this.loading = true + axios.get(heapDumpService(this.file, 'systemProperties')).then(resp => { + let sps = [] + for (let i in resp.data) { + sps.push({ + key: i, + value: resp.data[i] + }) + } + this.systemProperties = sps + this.loading = false + }) + }, + tableSpanMethod(i) { + if (i.columnIndex === 0) { + return [1, 1]; + } else if (i.columnIndex === 1) { + return [1, 2]; + } else { + return [0, 0] + } + }, + }, + data() { + return { + keyword: '', + systemProperties: [], + cellStyle: {padding: '0'}, + headerCellStyle: {'font-size': '12px', 'font-weight': 'normal'}, + loading: false, + } + }, + created() { + this.fetchSystemProperty() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/Thread.vue b/frontend/src/components/heapdump/Thread.vue new file mode 100644 index 0000000..42f6c1e --- /dev/null +++ b/frontend/src/components/heapdump/Thread.vue
@@ -0,0 +1,310 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <el-table ref="table" :data="threads" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + v-loading="loading" + height="100%" + :indent=8 + :load="loadStackInfo" + :span-method="tableSpanMethod"> + <el-table-column label="Thread / Stack" width="450px" show-overflow-tooltip> + <template slot-scope="scope"> + <span v-if="scope.row.isThread" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="threadIcon"/> {{scope.row.object}} + </span> + + <span v-if="scope.row.isStack"> + <img :src="frameIcon"/> {{scope.row.stack}} + </span> + + <span v-if="scope.row.isLocal" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon"> + <strong>{{ " " +scope.row.prefix + " "}}</strong> + {{scope.row.label}} + <span style="font-weight: bold; color: #909399">{{ " " + scope.row.suffix}}</span> + </span> + + <span v-if="scope.row.isOutbound" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="scope.row.icon"> + <strong>{{ " " +scope.row.prefix + " "}}</strong> + {{scope.row.label}} + <span style="font-weight: bold; color: #909399">{{ " " + scope.row.suffix}}</span> + </span> + + <span v-if="scope.row.isOutboundsSummary"> + <img :src="ICONS.misc.sumIcon" v-if="scope.row.currentSize >= scope.row.totalSize"/> + + <img :src="ICONS.misc.sumPlusIcon" + @dblclick="fetchOutbounds(scope.row.parentRowKey, scope.row.objectId, scope.row.nextPage, scope.row.resolve)" + style="cursor: pointer" + v-else/> + {{ scope.row.currentSize }} <strong> / </strong> {{ scope.row.totalSize }} + </span> + + <span v-if="scope.row.isThreadSummaryItem"> + <img :src="sumIcon" v-if="currentSize >= totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchThreadDetails" style="cursor: pointer" v-else/> + {{ currentSize }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + + <el-table-column label="Name" prop="name" width="300px" show-overflow-tooltip> + </el-table-column> + <el-table-column label="Shallow Heap" prop="shallowHeap"> + </el-table-column> + <el-table-column label="Retained Heap" prop="retainedHeap"> + </el-table-column> + <el-table-column label="Context Class Loader" prop="contextClassLoader" width="420px" show-overflow-tooltip> + </el-table-column> + <el-table-column label="Is Daemon" prop="daemon"> + </el-table-column> + </el-table> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + import {getOutboundIcon, ICONS} from './IconHealper' + + let rowKey = 1 + + export default { + props: ['file'], + methods: { + loadStackInfo(tree, treeNode, resolve) { + if (tree.isThread) { + this.fetchStackTrace(tree.objectId, resolve) + } else if (tree.isStack) { + this.fetchLocals(tree.threadObjectId, tree.depth, tree.firstNonNativeFrame, resolve) + } else if (tree.isLocal || tree.isOutbound) { + this.fetchOutbounds(tree.rowKey, tree.objectId, 1, resolve) + } else if (tree.isOutboundsSummary) { + this.fetchOutbounds(tree.parentRowKey, tree.objectId, tree.nextPage, resolve) + } + }, + tableSpanMethod(i) { + if (i.row.isStack) { + if (i.columnIndex === 0) { + return [1, 2]; + } else if (i.columnIndex === 1) { + return [0, 0]; + } else { + return [1, 1] + } + } + + if (i.row.isLocal || i.row.isOutbound) { + if (i.columnIndex === 0) { + return [1, 2]; + } else if (i.columnIndex === 1) { + return [0, 0]; + } else { + return [1, 1] + } + } + }, + fetchOutbounds(parentRowKey, objectId, page, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'outbounds'), { + params: { + objectId: objectId, + page: page, + pageSize: this.pageSize, + } + }).then(resp => { + let loadedLen = 0; + let loaded = this.$refs['table'].store.states.lazyTreeNodeMap[parentRowKey] + let callResolve = false + if (loaded) { + loadedLen = loaded.length + if (loadedLen > 0) { + loaded.splice(--loadedLen, 1) + } + } else { + loaded = [] + callResolve = true; + } + let res = resp.data.data + for (let i = 0; i < res.length; i++) { + loaded.push({ + rowKey: rowKey++, + isOutbound: true, + objectId: res[i].objectId, + prefix: res[i].prefix, + label: res[i].label, + suffix: res[i].suffix, + shallowHeap: res[i].shallowSize, + retainedHeap: res[i].retainedSize, + icon: getOutboundIcon(res[i].gCRoot, res[i].objectType), + hasChildren: res[i].hasOutbound + }) + } + + loaded.push({ + rowKey: rowKey++, + objectId: objectId, + parentRowKey: parentRowKey, + isOutboundsSummary: true, + nextPage: page + 1, + currentSize: loadedLen + res.length, + totalSize: resp.data.totalSize, + resolve: resolve, + }) + + if (callResolve) { + resolve(loaded) + } + this.loading = false + }) + + }, + fetchLocals(objId, depth, firstNonNativeFrame, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'locals'), { + params: { + objectId: objId, + depth: depth, + firstNonNativeFrame: firstNonNativeFrame + } + }).then(resp => { + let res = resp.data + let locals = [] + for (let i = 0; i < res.length; i++) { + locals.push({ + rowKey: rowKey++, + isLocal: true, + objectId: res[i].objectId, + prefix: res[i].prefix, + label: res[i].label, + suffix: res[i].suffix, + shallowHeap: res[i].shallowSize, + retainedHeap: res[i].retainedSize, + icon: getOutboundIcon(res[i].gCRoot, res[i].objectType), + hasChildren: res[i].hasOutbound + }) + } + resolve(locals) + this.loading = false + }) + }, + fetchStackTrace(objId, resolve) { + this.loading = true + axios.get(heapDumpService(this.file, 'stackTrace'), { + params: { + objectId: objId + } + }).then(resp => { + let res = resp.data + let stacks = [] + let depth = 1 + for (let i = 0; i < res.length; i++) { + stacks.push({ + rowKey: rowKey++, + isStack: true, + threadObjectId: objId, + stack: res[i].stack, + depth: depth++, + hasChildren: res[i].hasLocal, + firstNonNativeFrame: res[i].firstNonNativeFrame + }) + } + resolve(stacks) + this.loading = false + }) + }, + fetchThreadsData() { + this.loading = true + axios.get(heapDumpService(this.file, 'threadsSummary'), {}).then(resp => { + this.shallowHeap = resp.data.shallowHeap + this.retainedHeap = resp.data.retainedHeap + this.totalSize = resp.data.totalSize + this.fetchThreadDetails(); + }) + }, + fetchThreadDetails() { + if (this.currentSize >= this.totalSize) { + return + } + this.loading = true + if (this.nextPage > 1) { + this.threads.splice(this.threads.length - 1, 1) + } + axios.get(heapDumpService(this.file, 'threads'), { + params: { + page: this.nextPage, + pageSize: this.pageSize + } + }).then(resp => { + let res = resp.data.data + let tmp = [] + this.currentSize += res.length + for (let i = 0; i < res.length; i++) { + tmp.push({ + rowKey: rowKey++, + isThread: true, + objectId: res[i].objectId, + object: res[i].object, + name: res[i].name, + shallowHeap: res[i].shallowSize, + retainedHeap: res[i].retainedSize, + contextClassLoader: res[i].contextClassLoader, + daemon: res[i].daemon + '', + hasChildren: res[i].hasStack + }) + } + this.nextPage++ + tmp.forEach(t => this.threads.push(t)) + this.threads.push({ + rowKey: rowKey++, + isThreadSummaryItem: true, + shallowHeap: this.shallowHeap, + retainedHeap: this.retainedHeap + }) + this.loading = false + }) + } + }, + data() { + return { + loading: false, + threads: [], + ICONS, + threadIcon: require('../../assets/heap/thread.gif'), + frameIcon: require('../../assets/heap/stack_frame.gif'), + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + nextPage: 1, + pageSize: 25, + currentSize: 0, + totalSize: 0, + shallowHeap: 0, + retainedHeap: 0, + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'} + } + }, + created() { + this.fetchThreadsData() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/heapdump/UnreachableObjects.vue b/frontend/src/components/heapdump/UnreachableObjects.vue new file mode 100644 index 0000000..258aa3f --- /dev/null +++ b/frontend/src/components/heapdump/UnreachableObjects.vue
@@ -0,0 +1,143 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <div style="height: 100%"> + <el-table :data="tableData" + :highlight-current-row="false" + stripe + :header-cell-style="headerCellStyle" + :cell-style='cellStyle' + row-key="rowKey" + lazy + :span-method="spanMethod" + height="100%" + :indent=8 + v-loading="loading" + > + <el-table-column label="Class Name"> + <template slot-scope="scope"> + <span v-if="scope.row.isRecord" @click="$emit('setSelectedObjectId', scope.row.objectId)" + style="cursor: pointer"> + <img :src="classIcon"/> {{scope.row.className}} + </span> + + <span v-if="scope.row.isSummary"> + <img :src="sumIcon" v-if="records.length >= totalSize"/> + <img :src="sumPlusIcon" @dblclick="fetchRecords" style="cursor: pointer" v-else/> + {{ records.length }} <strong> / </strong> {{totalSize}} + </span> + </template> + </el-table-column> + + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + <el-table-column/> + + <el-table-column label="Objects" prop="objects"> + </el-table-column> + + <el-table-column label="Shallow Heap" prop="shallowSize"> + </el-table-column> + </el-table> + </div> +</template> + +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + + let rowKey = 1 + export default { + props: ['file'], + methods: { + spanMethod(row) { + let index = row.columnIndex + if (index === 0) { + return [1, 6] + } else if (index >= 1 && index <= 5) { + return [0, 0] + } + return [1, 1] + }, + fetchSummary() { + this.loading = true + axios.get(heapDumpService(this.file, 'unreachableObjects/summary')).then(resp => { + this.totalSize = resp.data.totalSize + this.objects = resp.data.objects + this.shallowSize = resp.data.shallowSize + if (this.totalSize > 0) { + this.fetchRecords() + } else { + this.loading = false + } + }) + }, + fetchRecords() { + this.loading = true + axios.get(heapDumpService(this.file, 'unreachableObjects/records'), { + params: { + page: this.nextPage, + pageSize: this.pageSize, + } + }).then(resp => { + let records = resp.data.data + records.forEach(record => this.records.push({ + rowKey: rowKey++, + + objectId: record.objectId, + className: record.className, + objects: record.objects, + shallowSize: record.shallowSize, + + isRecord: true, + })) + + this.tableData = this.records.concat({ + rowKey: rowKey++, + objects: this.objects, + shallowSize: this.shallowSize, + isSummary: true + }) + + this.nextPage++ + this.loading = false + }) + }, + }, + data() { + return { + classIcon: require('../../assets/heap/objects/class.gif'), + sumIcon: require('../../assets/heap/misc/sum.gif'), + sumPlusIcon: require('../../assets/heap/misc/sum_plus.gif'), + cellStyle: {padding: '4px', fontSize: '12px'}, + headerCellStyle: {padding: 0, 'font-size': '12px', 'font-weight': 'normal'}, + + loading: false, + + objects: 0, + shallowSize: 0, + + totalSize: 0, + nextPage: 1, + pageSize: 25, + records: [], + tableData: [], + } + }, + created() { + this.fetchSummary() + } + } +</script> \ No newline at end of file
diff --git a/frontend/src/components/menu/AnalysisResultMenu.vue b/frontend/src/components/menu/AnalysisResultMenu.vue new file mode 100644 index 0000000..14fe8c8 --- /dev/null +++ b/frontend/src/components/menu/AnalysisResultMenu.vue
@@ -0,0 +1,96 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <b-navbar-nav> + <b-nav-item href="#" @click="doReanalyze" v-if="analysisState === 'SUCCESS' || analysisState === 'ERROR'"> + <i class="el-icon-warning-outline" style="margin-right: 3px"/> {{$t("jifa.reanalyze")}} + </b-nav-item> + + <b-nav-item href="#" @click="doRelease" v-if="analysisState === 'SUCCESS'"> + <i class="el-icon-s-release" style="margin-right: 3px"/> {{$t("jifa.release")}} + </b-nav-item> + + <b-nav-item-dropdown right v-if="analysisState === 'SUCCESS' && type === 'HEAP_DUMP'"> + <template v-slot:button-content> + <i class="el-icon-setting" style="margin-right: 3px"/> {{$t("jifa.setting")}} + </template> + <b-dropdown-item @click="triggerInspector" style="font-size: 14px"> + {{showInspector ? $t("jifa.hide") : $t("jifa.show")}} Inspector + </b-dropdown-item> + <b-dropdown-item @click="$emit('expandResultDivWidth')" style="font-size: 14px"> + {{$t("jifa.expandResultDivWidth")}} + </b-dropdown-item> + <b-dropdown-item @click="$emit('shrinkResultDivWidth')" style="font-size: 14px"> + {{$t("jifa.shrinkResultDivWidth")}} + </b-dropdown-item> + <b-dropdown-item @click="$emit('resetResultDivWidth')" style="font-size: 14px"> + {{$t("jifa.resetResultDivWidth")}} + </b-dropdown-item> + </b-nav-item-dropdown> + </b-navbar-nav> +</template> +<script> + import axios from 'axios' + import {heapDumpService} from '../../util' + + export default { + props: ['file', 'analysisState', 'type', 'showInspector'], + + methods: { + + doReanalyze() { + this.$confirm(this.$t('jifa.heap.reanalyzePrompt'), this.$t('jifa.prompt'), { + confirmButtonText: this.$t('jifa.confirm'), + cancelButtonText: this.$t('jifa.cancel'), + type: 'warning' + }).then(() => { + axios.post(this.getUrlByType('clean')).then(() => { + window.location.reload(); + }) + }) + }, + + doRelease() { + this.$confirm(this.$t('jifa.heap.releasePrompt'), this.$t('jifa.prompt'), { + confirmButtonText: this.$t('jifa.confirm'), + cancelButtonText: this.$t('jifa.cancel'), + type: 'warning' + }).then(() => { + axios.post(this.getUrlByType('release')).then(() => { + this.$router.push({name: 'finder'}) + }) + }) + }, + + triggerInspector() { + if (this.type === "HEAP_DUMP") { + this.$emit('setShowInspector', !this.showInspector) + } + }, + + getUrlByType(uri) { + switch (this.type) { + case "HEAP_DUMP": + return heapDumpService(this.file, uri); + default: + return "" + } + } + } + } +</script> +<style scoped> + .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.5); + } +</style> \ No newline at end of file
diff --git a/frontend/src/components/menu/FinderMenu.vue b/frontend/src/components/menu/FinderMenu.vue new file mode 100644 index 0000000..ef4c3f2 --- /dev/null +++ b/frontend/src/components/menu/FinderMenu.vue
@@ -0,0 +1,45 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <b-navbar-nav> + + <b-nav-item @click="$emit('chooseMenu', 'HEAP_DUMP')" + :active="fileType==='HEAP_DUMP'"> + <i class="el-icon-coin" style="margin-right: 3px"/> {{$t("jifa.heapDumpAnalysis")}} + </b-nav-item> + + <b-nav-item @click="handleAddFile"> + <i class="el-icon-plus" style="margin-right: 3px"/> {{this.title}} + </b-nav-item> + </b-navbar-nav> +</template> + +<script> + + export default { + props: ['defaultActive', 'title', 'fileType'], + methods: { + handleAddFile() { + this.$emit('addFile'); + } + }, + data() { + return {} + }, + } +</script> +<style scoped> + .navbar-light .navbar-nav .nav-link.active { + color: #1989FA; + } +</style>
diff --git a/frontend/src/components/menu/ViewMenu.vue b/frontend/src/components/menu/ViewMenu.vue new file mode 100644 index 0000000..61977e7 --- /dev/null +++ b/frontend/src/components/menu/ViewMenu.vue
@@ -0,0 +1,76 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template> + <b-navbar type="light" variant="faded" style="height: 100%; border-bottom: 1px solid #dcdfe6; font-size: 14px"> + <b-navbar-nav> + <b-navbar-brand href="" to="/"> + <i class="el-icon-s-platform"/> + J I F A + </b-navbar-brand> + </b-navbar-nav> + + <finder-menu v-if="subject==='finder'" v-bind="$attrs" v-on="$listeners"/> + <analysis-result-menu v-else-if="subject==='analysisResult'" v-bind="$attrs" v-on="$listeners"/> + + <b-navbar-nav v-if="subject==='finder'" class="ml-auto"> + <b-nav-item-dropdown> + <template v-slot:button-content>{{currentLanguage}}</template> + <b-dropdown-item href="#" v-for="lang in supportLanguages" :key="lang" + @click="$i18n.locale=lang.value; currentLanguage=lang.label"> + {{lang.label}} + </b-dropdown-item> + </b-nav-item-dropdown> + </b-navbar-nav> + </b-navbar> +</template> + +<script> + import FinderMenu from "./FinderMenu"; + import AnalysisResultMenu from "./AnalysisResultMenu"; + + import {supportLanguages} from '../../i18n/i18n-setup' + + + export default { + props: ['subject'], + + components: { + FinderMenu, + AnalysisResultMenu, + }, + + methods: { + getCurrentLanguageLabel() { + for (let i = 0; i < supportLanguages.length; i++) { + let lang = supportLanguages[i] + if (lang.value === this.$i18n.locale) { + return lang.label + } + } + } + }, + + data() { + return { + supportLanguages, + currentLanguage: this.getCurrentLanguageLabel(), + } + }, + } +</script> + +<style scoped> + .navbar-light .navbar-nav .nav-link.active { + color: #1989FA; + } +</style>
diff --git a/frontend/src/components/transferFile.vue b/frontend/src/components/transferFile.vue new file mode 100644 index 0000000..3c2cf33 --- /dev/null +++ b/frontend/src/components/transferFile.vue
@@ -0,0 +1,447 @@ +<!-- + Copyright (c) 2020 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0 + + SPDX-License-Identifier: EPL-2.0 + --> +<template xmlns:v-clipboard="http://www.w3.org/1999/xhtml"> + <div style="margin-top: -20px"> + <el-dialog + width="30%" + title="Public Key" + :visible.sync="publicKeyViewVisible" + append-to-body> + <div style="margin-top: -20px"> + <el-button size="small" round v-clipboard:copy="publicKey" v-clipboard:success="publicKeyCopySuccessfully"> + {{$t('jifa.copy')}} + </el-button> + <el-input + type="textarea" + autosize + readonly + resize + v-model="publicKey" style="margin-top: 20px"> + </el-input> + </div> + </el-dialog> + + <el-dialog + width="30%" + :visible.sync="transferProgressViewVisible" + :before-close="closeProgressView" + :close-on-press-escape=false :close-on-click-modal=false + append-to-body> + <el-row> + <el-col :span="24" align="center"> + <el-progress type="circle" :percentage=transferProgress :status="transferState" + v-if="totalSize > 0"></el-progress> + <b-spinner variant="secondary" type="grow" v-if="totalSize < 0"></b-spinner> + </el-col> + </el-row> + <div style="margin-top: 8px;"> + <p align="center" style="font-size: 14px"><strong>{{currentProgress}}</strong></p> + </div> + + <b-card class="mt-3" bg-variant="dark" text-variant="white" v-if="transferErrorMessage" style="margin-top: 20px"> + <p style="font-size: 14px; white-space: pre-line;"> + {{transferErrorMessage}} + </p> + </b-card> + </el-dialog> + + <el-tabs value="upload" style="margin-top: 10px"> + <el-tab-pane label="Upload" name="upload"> + <div align="center"> + <el-upload ref="uploadComp" + drag + :limit=1 + :data="{type: fileType}" + :action="service('/file/upload')" + :multiple=false + :on-success="onSuccess"> + <i class="el-icon-upload"></i> + <div class="el-upload__text">{{ $t('jifa.uploadPrompt') }}</div> + </el-upload> + </div> + </el-tab-pane> + + <el-tab-pane label="S C P" name="scp"> + + <el-form ref="scpForm" :model="scp" :rules="scpRules" label-width="150px" size="medium" label-position="right" + style="margin-top: 10px" :show-message=false status-icon> + + <el-form-item label=""> + <el-radio-group v-model="scp.authType" @change="changeAuthType"> + <el-radio label="publicKey">Public Key</el-radio> + <el-radio label="password">Password</el-radio> + </el-radio-group> + </el-form-item> + + <el-form-item label="Hostname" prop="hostname"> + <el-input v-model="scp.hostname" placeholder="Hostname" style="width: 60%" clearable></el-input> + </el-form-item> + + <el-form-item label="Path" prop="path"> + <el-input v-model="scp.path" placeholder="Path" style="width: 60%" clearable></el-input> + </el-form-item> + + <el-form-item label="User" prop="user"> + <el-input v-model="scp.user" placeholder="User" style="width: 60%" clearable></el-input> + </el-form-item> + + <el-form-item label="Password" v-if="scp.authType === 'password'" prop="password"> + <el-input v-model="scp.password" placeholder="Password" style="width: 60%" clearable + show-password></el-input> + </el-form-item> + + <el-form-item label="Public Key" v-if="scp.authType === 'publicKey'"> + <el-button icon="el-icon-view" round @click="loadPublicKey" style="outline:none;"></el-button> + </el-form-item> + + <el-form-item> + <el-button type="primary" @click="scpConfirm" :disabled="inTransferring">{{$t('jifa.confirm')}}</el-button> + </el-form-item> + + </el-form> + </el-tab-pane> + + <el-tab-pane label="U R L" name="url"> + <el-form ref="urlForm" :model="url" :rules="urlRules" label-width="150px" size="medium" label-position="right" + style="margin-top: 10px" :show-message=false status-icon> + <el-form-item label="U R L" prop="url" :show-message=false> + <el-input v-model="url.url" placeholder="U R L" style="width: 80%" clearable></el-input> + </el-form-item> + + <el-form-item> + <el-button type="primary" @click="urlConfirm" :disabled="inTransferring">{{$t('jifa.confirm')}}</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + + <el-tab-pane label="File System" name="fileSystem"> + <el-form ref="fileSystemForm" :model="fileSystem" :rules="fileSystemRules" label-width="150px" size="medium" + label-position="right" + style="margin-top: 10px" :show-message=false status-icon> + <el-form-item label=""> + <el-radio-group v-model="fileSystem.moveOrCopy"> + <el-radio label="move">Move</el-radio> + <el-radio label="copy">Copy</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="Path" prop="path" :show-message=false> + <el-input v-model="fileSystem.path" placeholder="path" style="width: 80%" clearable></el-input> + </el-form-item> + + <el-form-item> + <el-button type="primary" @click="fileSystemConfirm" :disabled="inTransferring">{{$t('jifa.confirm')}}</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + + <el-tab-pane label="O S S" name="oss"> + <el-form ref="ossForm" :model="oss" :rules="ossRules" label-width="150px" size="medium" label-position="right" + style="margin-top: 10px" status-icon :show-message=false> + <el-form-item label="Endpoint" prop="endpoint"> + <el-input v-model="oss.endpoint" placeholder="Endpoint" style="width: 80%" clearable></el-input> + </el-form-item> + + <el-form-item label="Access Key Id" prop="accessKeyId"> + <el-input v-model="oss.accessKeyId" placeholder="Access Key Id" style="width: 80%" clearable + show-password=""></el-input> + </el-form-item> + + <el-form-item label="Access Key Secret" prop="accessKeySecret"> + <el-input v-model="oss.accessKeySecret" placeholder="Access Key Secret" style="width: 80%" clearable + show-password=""></el-input> + </el-form-item> + + <el-form-item label="Bucket Name" prop="bucketName"> + <el-input v-model="oss.bucketName" placeholder="Bucket Name" style="width: 80%" clearable></el-input> + </el-form-item> + + <el-form-item label="Object Name" prop="objectName"> + <el-input v-model="oss.objectName" placeholder="Object Name" style="width: 80%" clearable></el-input> + </el-form-item> + + <el-form-item> + <el-button type="primary" @click="ossConfirm" :disabled="inTransferring">{{$t('jifa.confirm')}}</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + + </el-tabs> + + + </div> +</template> + +<script> + import axios from 'axios' + import {service, toSizeString} from '../util' + + export default { + props: ['fileType', 'transferViewVisible'], + data() { + return { + url: { + url: '', + }, + urlRules: { + url: [ + {required: true, trigger: 'blur'} + ], + }, + fileSystem: { + path: '', + moveOrCopy: 'move', + }, + fileSystemRules: { + path: [ + {required: true, trigger: 'blur'} + ], + }, + scp: { + user: '', + authType: 'publicKey', + password: '', + hostname: '', + path: '', + }, + scpRules: { + user: [ + {required: true, trigger: 'blur'} + ], + password: [ + {required: true, trigger: 'blur'} + ], + hostname: [ + {required: true, trigger: 'blur'} + ], + path: [ + {required: true, trigger: 'blur'} + ], + }, + oss: { + endpoint: '', + accessKeyId: '', + accessKeySecret: '', + bucketName: '', + objectName: '' + }, + ossRules: { + endpoint: [ + {required: true, trigger: 'blur'} + ], + accessKeyId: [ + {required: true, trigger: 'blur'} + ], + accessKeySecret: [ + {required: true, trigger: 'blur'} + ], + bucketName: [ + {required: true, trigger: 'blur'} + ], + objectName: [ + {required: true, trigger: 'blur'} + ], + }, + + publicKeyViewVisible: false, + publicKey: '', + + transferProgressViewVisible: false, + transferProgress: 0, + transferState: null, + transferErrorMessage: '', + currentProgress: '', + lastTransferredSize: 0, + transferredSize: 0, + totalSize: 0, + transferSpeed: 0, + fileName: '', + pollingInternal: 1000, + + inTransferring: false, + } + }, + methods: { + service, + changeAuthType(authType) { + this.$refs['scpForm'].clearValidate() + this.scpRules.password[0].required = authType === 'password' + }, + loadPublicKey() { + if (!this.publicKey) { + axios.get(service('/publicKey')).then(resp => { + this.publicKey = resp.data + }) + } + this.publicKeyViewVisible = true + }, + publicKeyCopySuccessfully() { + this.$message( + { + duration: 1000, + message: this.$t('jifa.copySuccessfully') + }); + }, + urlConfirm() { + this.$refs['urlForm'].validate((valid) => { + if (valid) { + let formData = new FormData() + formData.append('url', this.url.url) + this.doTransfer('/file/transferByURL', formData) + } + }) + }, + fileSystemConfirm() { + this.$refs['fileSystemForm'].validate((valid) => { + if (valid) { + let formData = new FormData() + formData.append('path', this.fileSystem.path) + formData.append('move', this.fileSystem.moveOrCopy === 'move') + this.doTransfer('/file/transferByFileSystem', formData) + } + }) + }, + scpConfirm() { + this.$refs['scpForm'].validate((valid) => { + if (valid) { + let usePublicKey = this.scp.authType === 'publicKey' + let formData = new FormData() + formData.append('hostname', this.scp.hostname) + formData.append('path', this.scp.path) + formData.append('user', this.scp.user) + formData.append('usePublicKey', usePublicKey) + if (!usePublicKey) { + formData.append('password', this.scp.password) + } + this.doTransfer('/file/transferBySCP', formData) + } + }) + }, + ossConfirm() { + this.$refs['ossForm'].validate((valid) => { + if (valid) { + let formData = new FormData() + formData.append('endpoint', this.oss.endpoint) + formData.append('accessKeyId', this.oss.accessKeyId) + formData.append('accessKeySecret', this.oss.accessKeySecret) + formData.append('bucketName', this.oss.bucketName) + formData.append('objectName', this.oss.objectName) + this.doTransfer('/file/transferByOSS', formData) + } + }) + }, + jmxConfirm() { + this.$refs['jmxForm'].validate((valid) => { + if (valid) { + let formData = new FormData(); + formData.append('host', this.jmx.host); + formData.append('port', this.jmx.port); + this.doTransfer('/file/createJmxConn', formData) + } + }) + }, + onSuccess() { + this.transferState = 'success' + this.inTransferring = false + this.$notify({ + title: this.$t('jifa.success'), + type: 'success', + duration: 1500, + onClose: () => { + // clean + if (this.$jifa.dev() && this.$refs['uploadComp']!=null) { + this.$refs['uploadComp'].clearFiles() + } + this.publicKeyViewVisible = false + this.transferProgressViewVisible = false + this.transferProgress = 0 + this.transferState = null + this.transferErrorMessage = '' + this.currentProgress = '' + this.lastTransferredSize = 0 + this.transferredSize = 0 + this.totalSize = 0 + this.transferSpeed = 0 + this.fileName = '' + this.$emit('transferFileFinishNotify'); + } + }); + }, + transferProgressPoll() { + let self = this; + if (!self || self._isDestroyed) { + return + } + axios.get(service('/file/transferProgress'), { + params: { + name: this.fileName, + type: this.fileType + } + }).then(resp => { + let progress = resp.data + this.totalSize = progress.totalSize + this.lastTransferredSize = this.transferredSize + this.transferredSize = progress.transferredSize + this.currentProgress = toSizeString((this.transferredSize - this.lastTransferredSize) / (this.pollingInternal / 1000)) + + '/s ' + + "[" + toSizeString(this.transferredSize) + + ", " + (this.totalSize > 0 ? toSizeString(this.totalSize) : " ? ") + "]" + if (progress.percent <= 1) { + this.transferProgress = parseFloat((progress.percent * 100).toPrecision(3)) + } else { + this.transferProgress = 99.9 + } + if (progress.state === 'SUCCESS') { + this.onSuccess() + } else if (progress.state === 'ERROR') { + this.transferState = 'exception' + this.transferErrorMessage = progress.message + this.inTransferring = false + } else if (progress.state === 'IN_PROGRESS' || progress.state === 'NOT_STARTED') { + setTimeout(this.transferProgressPoll, this.pollingInternal) + } + }) + + }, + doTransfer(api, formData) { + this.inTransferring = true + this.currentProgress = '0 [0, 0]' + this.transferProgress = 0 + this.transferState = null + this.transferErrorMessage = '' + this.totalSize = 0 + this.transferredSize = 0 + this.lastTransferredSize = 0 + + formData.append('type', this.fileType) + axios.post(service(api), new URLSearchParams(formData)).then(resp => { + this.fileName = resp.data.name + this.transferProgressViewVisible = true + this.transferProgressPoll() + }).catch(e => { + this.transferState = 'exception' + this.transferErrorMessage = e.response.data.message + this.transferProgressViewVisible = true + this.inTransferring = false + }) + }, + closeProgressView(done) { + this.$confirm(this.$t('jifa.close') + this.$t('jifa.qm'), '', { + confirmButtonText: this.$t('jifa.confirm'), + cancelButtonText: this.$t('jifa.cancel'), + }).then(() => { + done(); + }) + }, + } + } +</script>
diff --git a/frontend/src/i18n/cn.js b/frontend/src/i18n/cn.js new file mode 100644 index 0000000..439bc3d --- /dev/null +++ b/frontend/src/i18n/cn.js
@@ -0,0 +1,116 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +'use strict'; + +exports.__esModule = true; +exports.default = { + jifa: { + heapDumpAnalysis: '堆分析', + + setting: '设置', + diskCleanup: '清理磁盘', + help: '帮助', + consoleMsg: '', + getStarted: '开始使用', + success: '成功', + console: '控制台', + setUserWorker: '设置 Worker 地址', + qm: '?', + feedback: '建议与反馈', + options: '选项', + optionsWithHelp: '选项', + close: '关闭', + uploadPrompt: '选择文件(拖拽或点击选择)', + enterPrompt: '请输入', + inLine: '排队中', + addFile: '添加文件', + addHeapDumpFile:'添加 Heap Dump', + copy: '复制', + copySuccessfully: '复制成功', + requestFailed: '请求失败', + config: '配置', + prompt: '提示', + confirm: '确定', + reset: '重置', + cancel: '取消', + fileTransfer: '文件传输', + progress: '进度', + analyze: '分析', + reanalyze: '重新分析', + release: '释放', + edit: '编辑', + delete: '删除', + loading: '加载中', + goToOverViewPrompt: '即将进入概况页面...', + deletePrompt: '此操作将永久删除该文件,是否继续?', + deleteSuccessPrompt: '删除成功!', + deleteFailedPrompt: '删除失败!', + deleteCanceled: '已取消删除', + returnValue: '确定离开吗?', + gotoParseFile: '即将解析文件', + + typeKeyWord: '输入关键字搜索', + + transferring: '传输中', + transferError: '传输失败', + + show: '显示', + hide: '隐藏', + + expandResultDivWidth: '显示宽度 Expand', + shrinkResultDivWidth: '显示宽度 Shrink', + resetResultDivWidth: '显示宽度 Reset', + + heap: { + basicInformation: '基础信息', + reanalyzePrompt: '是否继续?', + releasePrompt: '是否继续?', + overview: '概况', + leakSuspects: '泄露报表', + description: '描述', + detail: '细节', + GCRoots: 'GC 根对象', + systemProperty: '系统属性', + OSBit: '操作系统位数', + jvmInfo: 'JVM', + heapCreationDate: '创建时间', + usedHeapSize: '堆使用大小', + numberOfClasses: '类数量', + numberOfObjects: '对象数量', + numberOfClassLoaders: '类加载器数量', + numberOfGCRoots: '根对象数量', + threadInfo: '线程信息', + dominatorTree: '支配树', + histogram: '类视图', + unreachableObjects: '不可达类视图', + duplicatedClasses: '重复类视图', + classLoaders: '类加载器视图', + directByteBuffer: '堆外内存视图', + compare: '内存文件对比', + ref: { + object: { + label: '对象引用', + outgoing: '引用对象集合', + incoming: '被引用对象集合', + }, + type: { + label: '类型引用', + outgoing: '引用类型集合', + incoming: '被引用类型集合', + } + }, + + pathToGCRoots: 'GC 根路径', + }, + } +}; \ No newline at end of file
diff --git a/frontend/src/i18n/en.js b/frontend/src/i18n/en.js new file mode 100644 index 0000000..55c03c7 --- /dev/null +++ b/frontend/src/i18n/en.js
@@ -0,0 +1,118 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +'use strict'; + +exports.__esModule = true; +exports.default = { + jifa: { + heapDumpAnalysis: 'Heap Dump Analysis', + + setting: 'Setting', + diskCleanup: 'Disk Cleanup', + help: 'Help', + consoleMsg: '', + getStarted: 'Get Started', + success: 'Success', + console: 'Console', + setUserWorker: 'Set Worker', + qm: '?', + feedback: 'Feedback', + options: 'Options', + optionsWithHelp: 'Options', + close: 'Close', + uploadPrompt: 'Choose your file (drag or click)', + enterPrompt: 'Please enter ', + inLine: 'In Line', + addFile: 'Add File', + addHeapDumpFile:'Add Heap Dump File', + copy: 'Copy', + copySuccessfully: 'Copy Successfully', + requestFailed: 'Request failed', + config: 'Config', + prompt: 'Prompt', + confirm: 'Confirm', + reset: 'Reset', + cancel: 'Cancel', + fileTransfer: 'File Transfer', + progress: 'Progress', + analyze: 'analyze', + reanalyze: 'Reanalyze', + release: 'Release', + edit: 'edit', + delete: 'Delete', + loading: 'Loading', + goToOverViewPrompt: 'Go to the overview page', + deletePrompt: 'This will permanently delete the file. Do you want to continue?', + deleteSuccessPrompt: 'Delete success!', + deleteFailedPrompt: 'Delete failed!', + deleteCanceled: 'Delete operation is canceled', + returnValue: 'Are you sure to leave?', + gotoParseFile: 'Will go to parse file', + + typeKeyWord: 'type key word to search', + + transferring: 'transferring', + transferError: 'transfer error', + + show: 'Show', + hide: 'Hide', + + expandResultDivWidth: 'Expand Width', + shrinkResultDivWidth: 'Shrink Width', + resetResultDivWidth: 'Reset Width', + + addResultDivWidth: 'Add width', + + heap: { + basicInformation: 'Basic Information', + reanalyzePrompt: 'Do you want to continue?', + releasePrompt: 'Do you want to continue?', + overview: 'Overview', + leakSuspects: 'Leak Suspects', + description: 'Description', + detail: 'Detail', + GCRoots: 'GC Roots', + systemProperty: 'System Property', + OSBit: 'OS Bit', + jvmInfo: 'JVM', + heapCreationDate: 'Creation Date', + usedHeapSize: 'Used Heap Size', + numberOfClasses: 'Class Count', + numberOfObjects: 'Object Count', + numberOfClassLoaders: 'Class Loaders Count', + numberOfGCRoots: 'GC Root Count', + threadInfo: 'Thread Info', + dominatorTree: 'Dominator Tree', + histogram: 'Histogram', + unreachableObjects: 'Unreachable Objects', + duplicatedClasses: 'Duplicated Classes', + classLoaders: 'Class Loaders', + directByteBuffer: 'Direct Byte Buffer', + compare: 'Heap File Compare', + ref: { + object: { + label: 'References by Object', + outgoing: 'outgoing references', + incoming: 'incoming references', + }, + type: { + label: 'Reference by Class', + outgoing: 'outgoing references', + incoming: 'incoming references', + } + }, + + pathToGCRoots: 'Path to GC Roots', + }, + } +}; \ No newline at end of file
diff --git a/frontend/src/i18n/i18n-setup.js b/frontend/src/i18n/i18n-setup.js new file mode 100644 index 0000000..792ba30 --- /dev/null +++ b/frontend/src/i18n/i18n-setup.js
@@ -0,0 +1,38 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +import Vue from 'vue' +import VueI18n from 'vue-i18n' +import messages from './messages' + +import ElementLocale from 'element-ui/lib/locale' + +Vue.use(VueI18n) + +const i18n = new VueI18n({ + fallbackLocale: 'en', + messages +}) + +i18n.locale = 'en' + +ElementLocale.i18n((key, value) => i18n.t(key, value)) + +export default i18n + +export const supportLanguages = [{ + label: 'English', + value: 'en' +}, { + label: '中文', + value: 'cn' +},]
diff --git a/frontend/src/i18n/messages.js b/frontend/src/i18n/messages.js new file mode 100644 index 0000000..d014cde --- /dev/null +++ b/frontend/src/i18n/messages.js
@@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +import element_ui_enLocale from 'element-ui/lib/locale/lang/en' +import element_ui_zhLocale from 'element-ui/lib/locale/lang/zh-CN' + +import en from './en' +import cn from './cn' + +export default { + en: { + ...en, + ...element_ui_enLocale, + }, + + cn: { + ...cn, + ...element_ui_zhLocale + } +} \ No newline at end of file
diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..5cf20bf --- /dev/null +++ b/frontend/src/main.js
@@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +import Vue from 'vue' + +import Jifa from './Jifa.vue' +import JifaGlobal from './Jifa' + +import i18n from './i18n/i18n-setup' +import router from './router' + +import ElementUI from 'element-ui' +import BootstrapVue from 'bootstrap-vue' +import VueCharts from 'vue-chartjs' +import VueClipboard from 'vue-clipboard2' +import contentmenu from 'v-contextmenu' + +import VueCookies from 'vue-cookies' + +import 'v-contextmenu/dist/index.css' +import 'bootstrap/dist/css/bootstrap.css' +import 'bootstrap-vue/dist/bootstrap-vue.css' +import 'element-ui/lib/theme-chalk/index.css' +// put our css file in the end +import './Jifa.css' + +Vue.use(ElementUI) +Vue.use(BootstrapVue) +Vue.use(VueCharts) +Vue.use(VueClipboard) +Vue.use(contentmenu) +Vue.use(VueCookies) +Vue.prototype.$jifa = JifaGlobal + +export default new Vue({ + router, + i18n, + render: h => h(Jifa), + created() { + console.log(this.$t("jifa.consoleMsg")) + } +}).$mount('#app') \ No newline at end of file
diff --git a/frontend/src/router.js b/frontend/src/router.js new file mode 100644 index 0000000..b8790d6 --- /dev/null +++ b/frontend/src/router.js
@@ -0,0 +1,75 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +import Vue from "vue" + +import VueRouter from "vue-router" + +import finder from "./components/finder" + +import heapDump from "./components/heapdump/HeapDump" + +import axios from "axios"; + +import notFound from "./components/404" + +import VueInsatence from "./main" + +Vue.use(VueRouter) + +const routes = [ + { + name: 'finder', + path: '/', + component: finder + }, + { + name: 'heapDump', + path: "/heapDump", + component: heapDump, + props: (route) => ({file: route.query.file}) + }, + {path: '*', component: notFound} +]; + +const router = new VueRouter({ + mode: 'history', + routes +}); + +axios.interceptors.response.use(function (response) { + return response; +}, function (error) { + let resp = error.response + if (resp) { + let status = resp.status + let data = resp.data + if (status === 500 || status === 400 || status === 401 || status === 403) { + if (data && data.hasOwnProperty('errorCode')) { + if (data.errorCode === 'TRANSFER_ERROR') { + // do nothing + } else { + VueInsatence.$notify.error({ + title: data.errorCode, + message: data.message, + offset: 100, + duration: 0, + showClose: true + }); + } + } + } + } + return Promise.reject(error); +}); + +export default router \ No newline at end of file
diff --git a/frontend/src/util.js b/frontend/src/util.js new file mode 100644 index 0000000..6df9691 --- /dev/null +++ b/frontend/src/util.js
@@ -0,0 +1,76 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +export function toSizeString(bytes) { + if (bytes <= 1024) return bytes + " B" + let k = 1024, + suffix = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], + i = Math.floor(Math.log(bytes) / Math.log(k)) + + return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + suffix[i] +} + +export function toCountString(counts) { + if (counts <= 1000) return counts + " " + let k = 1000, + suffix = [' ', 'k', 'm', 'g', 't', 'p', 'e', 'z', 'y'], + i = Math.floor(Math.log(counts) / Math.log(k)) + + return (counts / Math.pow(k, i)).toPrecision(4) + ' ' + suffix[i] +} + +const SERVICE_PREFIX = '/jifa-api' + +export function service(suffix) { + return SERVICE_PREFIX + suffix +} + +export function heapDumpService(file, api) { + return SERVICE_PREFIX + '/heap-dump/' + file + '/' + api; +} + +export function matchSearch(data,val){ + let temp = []; + for(let index in data){ + for(let prop in data[index]){ + // Do not use strict equal operator + if(data[index][prop]==val){ + temp.push(data[index]); + } + } + } + return temp; +} + +// e.g. formatTime(1545903266795, 'Y-M-D h:m:s') +export function formatTime (number, format) { + let time = new Date(number) + let newArr = [] + let formatArr = ['Y', 'M', 'D', 'h', 'm', 's'] + newArr.push(time.getFullYear()) + newArr.push(formatNumber(time.getMonth() + 1)) + newArr.push(formatNumber(time.getDate())) + + newArr.push(formatNumber(time.getHours())) + newArr.push(formatNumber(time.getMinutes())) + newArr.push(formatNumber(time.getSeconds())) + + for (let i in newArr) { + format = format.replace(formatArr[i], newArr[i]) + } + return format; +} + +function formatNumber (n) { + n = n.toString() + return n[1] ? n : '0' + n; +} \ No newline at end of file
diff --git a/frontend/vue.config.js b/frontend/vue.config.js new file mode 100644 index 0000000..e9aa8bf --- /dev/null +++ b/frontend/vue.config.js
@@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +module.exports = { + devServer: { + historyApiFallback: { + disableDotRule: true + }, + noInfo: true, + port: 8089, + proxy: { + '/jifa-api': { + target: 'http://127.0.0.1:8102' + }, + } + }, + publicPath: './' +} \ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..87b738c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9b86d1c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@ +#Fri Mar 22 09:38:02 CST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..af6708f --- /dev/null +++ b/gradlew
@@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..6d57edc --- /dev/null +++ b/gradlew.bat
@@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega
diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..512de6d --- /dev/null +++ b/settings.gradle
@@ -0,0 +1,18 @@ +/******************************************************************************** + * Copyright (c) 2020 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +rootProject.name = 'Jifa' + +include ':frontend' +include ':backend' +include ':backend:common' +include ':backend:worker'