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",