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"/> &nbsp;</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'