You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by nv...@apache.org on 2022/04/22 11:48:25 UTC

[cloudstack] branch main updated: Mshost stats (#5588)

This is an automated email from the ASF dual-hosted git repository.

nvazquez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 545e89c1cb Mshost stats (#5588)
545e89c1cb is described below

commit 545e89c1cb564dbec7ba8e122f6bab77cdcbdfd1
Author: dahn <da...@shapeblue.com>
AuthorDate: Fri Apr 22 13:48:19 2022 +0200

    Mshost stats (#5588)
    
    * ms stats thread added
    
    * initial data collection for management server
    
    * empty list management server metrics command
    
    * bean copy into MS metrics object
    
    * ms status VO
    
    * further API and DB plumbing
    
    * minimal metrics response in API
    
    * remove commented, refactor data collection plumbing
    
    * javadocs
    
    * surpress stacktrace on expected error
    
    * update status experiment
    
    * ms status publish framework added
    
    * review comment addressed
    
    * static data to DB and API, /proc/ reading
    
    * addressing review comments
    
    * ui for ms details
    
    * small ui adjustment
    
    * beanCopy
    
    * agentcount response and system parameter
    
    * labels
    
    * package-lock
    
    * add version strings to regular list API
    
    * add shutdown time to DB
    
    * add last start and last stop to regular list response
    
    * distro info in regular response/session  count added
    
    * metrics as details
    
    * add heap used and remove details map
    
    * thread-statusses
    
    * move db upgrade to 4.17
    
    * sysmem
    
    * procmem
    
    * ui demo comments applied
    
    * javadoc
    
    * get conf and log file locations
    
    * loginfo
    
    * cpuLoadStats
    
    * no.remote
    
    * extra spaces removed
    
    * clusterlistener
    
    * add unit to kb value
    
    * revert accidental rename
    
    * silly fqcn removed
    
    * get mem info from bean is possible
    
    * refactor long sequence for readability
    
    * registerListener
    
    * listUsageMetrics and isDbLocal
    
    * rats
    
    * local usage and db or not
    
    * minimal listDbMetrics
    
    * db vars and stats
    
    * cleanup and #queries queried
    
    * db stats calculation
    
    * rat
    
    * remove list response wrapper from sinlge details-lists responses
    
    * rudimentary metrics view
    
    * metrics table cleanup
    
    * table makeup, collection dates
    
    * move component to appropriate location
    
    * capitalisation removed
    
    * rebase error resolved
    
    * rename deamon to daemon
    
    * small style comments applied
    
    * another merge issue
    
    * naming comments and boot time
    
    * stop/start prefixed with server
    
    * layout-fix
    
    * listMSMetrics test and test refactor
    
    * usage metrics test
    
    * db metrics test
    
    * extra validations
    
    * Update ui/public/locales/en.json
    
    Co-authored-by: sureshanaparti <12...@users.noreply.github.com>
    
    * descriptions of loadaverages and replica's
    
    * collection time on top
    
    * cpu load on metrics overview
    
    * DbStatsCollection
    
    * some parameter description texts
    
    * labels adjusted
    
    * new output 'kernelversion' and log info cleanup
    
    * labels
    
    * Update api/src/main/java/com/cloud/server/ManagementServerHostStats.java
    
    Co-authored-by: sureshanaparti <12...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/response/DbMetricsResponse.java
    
    Co-authored-by: sureshanaparti <12...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java
    
    Co-authored-by: Rodrigo D. Lopez <19...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
    
    Co-authored-by: Rodrigo D. Lopez <19...@users.noreply.github.com>
    
    * Update api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update server/src/main/java/com/cloud/server/StatsCollector.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update server/src/main/java/com/cloud/server/StatsCollector.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update server/src/main/java/com/cloud/server/StatsCollector.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update server/src/main/java/com/cloud/server/StatsCollector.java
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    * Update plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
    
    * some (more) refactorring suggestions applied
    
    * human readable memory sizes
    
    * rat
    
    * actual collection time instead of query time, improved descriptions
    
    * merge errors fixed
    
    * optional metric values
    
    * javadoc and logging
    
    * names of jmx vars have changed
    
    * vue3-compatibility
    
    * new output parameter type
    
    * lower retention default
    
    * vue3 fixes
    
    * polish comments
    
    * polish comments 2, the reckoning
    
    * note on usage servers
    
    * merge conflict errors
    
    * pollish
    
    * conditional assertion to deal with simulator restart
    
    Co-authored-by: Daan Hoogland <da...@onecht.net>
    Co-authored-by: sureshanaparti <12...@users.noreply.github.com>
    Co-authored-by: Rodrigo D. Lopez <19...@users.noreply.github.com>
    Co-authored-by: Daniel Augusto Veronezi Salvador <38...@users.noreply.github.com>
    Co-authored-by: Rohit Yadav <ro...@shapeblue.com>
---
 .../cloud/server/ManagementServerHostStats.java    |   113 +
 .../org/apache/cloudstack/api/ApiConstants.java    |     9 +-
 .../api/response/ManagementServerResponse.java     |   103 +-
 .../management/ManagementServerStatus.java         |    45 +
 client/src/main/webapp/WEB-INF/web.xml             |     3 +
 .../cloud/agent/manager/ConnectedAgentAttache.java |     2 +-
 .../src/main/java/com/cloud/host/dao/HostDao.java  |     7 +
 .../main/java/com/cloud/host/dao/HostDaoImpl.java  |    12 +
 .../spring-engine-schema-core-daos-context.xml     |     2 +
 .../resources/META-INF/db/schema-41610to41700.sql  |    84 +-
 .../java/com/cloud/cluster/ClusterManager.java     |    52 +-
 .../java/com/cloud/cluster/ClusterManagerImpl.java |    56 +-
 .../java/com/cloud/cluster/ClusterServicePdu.java  |     1 +
 .../cloud/cluster/ManagementServerStatusVO.java    |   184 +
 .../cloud/cluster/dao/ManagementServerHostDao.java |     7 +-
 .../cluster/dao/ManagementServerStatusDao.java     |    24 +
 .../cluster/dao/ManagementServerStatusDaoImpl.java |    48 +
 .../src/main/java/com/cloud/utils/db/DbUtil.java   |    42 +-
 .../web/CloudStackContextLoaderListener.java       |     3 +-
 .../apache/cloudstack/api/ListDbMetricsCmd.java    |    56 +
 .../apache/cloudstack/api/ListMgmtsMetricsCmd.java |    56 +
 .../cloudstack/api/ListUsageServerMetricsCmd.java  |    57 +
 .../org/apache/cloudstack/api/MetricConstants.java |    56 +
 .../apache/cloudstack/metrics/MetricsService.java  |     8 +
 .../cloudstack/metrics/MetricsServiceImpl.java     |   379 +-
 .../response/ClusterMetricsResponse.java           |     2 +-
 .../cloudstack/response/DbMetricsResponse.java     |   107 +
 .../cloudstack/response/HostMetricsSummary.java    |    51 +
 .../response/ManagementServerMetricsResponse.java  |   211 +
 .../response/UsageServerMetricsResponse.java       |    68 +
 .../cloudstack/response/ZoneMetricsResponse.java   |     2 +-
 .../cloudstack/metrics/MetricsServiceImplTest.java |     2 +
 server/pom.xml                                     |    10 +
 server/src/main/java/com/cloud/api/ApiDBUtils.java |     9 +
 .../java/com/cloud/api/ApiSessionListener.java     |    90 +
 .../java/com/cloud/api/query/QueryManagerImpl.java |    42 +-
 .../api/query/dao/ManagementServerJoinDao.java     |    23 +
 .../api/query/dao/ManagementServerJoinDaoImpl.java |    23 +
 .../cloud/api/query/vo/ManagementServerJoinVO.java |   173 +
 .../java/com/cloud/server/DbStatsCollection.java   |    31 +
 .../server/ManagementServerHostStatsEntry.java     |   456 +
 .../main/java/com/cloud/server/StatsCollector.java |   808 +-
 server/src/test/async-job-component.xml            |     1 +
 .../java/com/cloud/server/StatsCollectorTest.java  |    53 +-
 test/integration/smoke/test_metrics_api.py         |   229 +-
 ui/package-lock.json                               | 32845 ++++++++++++++++++-
 ui/public/locales/el_GR.json                       |     1 -
 ui/public/locales/en.json                          |    36 +-
 ui/src/components/view/DetailsTab.vue              |     2 +-
 ui/src/config/section/infra.js                     |    13 +-
 ui/src/config/section/infra/managementServers.js   |    41 +
 ui/src/core/lazy_lib/icons_use.js                  |     6 +
 ui/src/views/AutogenView.vue                       |     2 +-
 ui/src/views/infra/InfraSummary.vue                |     2 +-
 ui/src/views/infra/Metrics.vue                     |   235 +
 utils/src/main/java/com/cloud/utils/LogUtils.java  |    40 +-
 56 files changed, 36408 insertions(+), 615 deletions(-)

diff --git a/api/src/main/java/com/cloud/server/ManagementServerHostStats.java b/api/src/main/java/com/cloud/server/ManagementServerHostStats.java
new file mode 100644
index 0000000000..1f201d7689
--- /dev/null
+++ b/api/src/main/java/com/cloud/server/ManagementServerHostStats.java
@@ -0,0 +1,113 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.server;
+
+import java.util.Date;
+
+/**
+ * management server related stats
+ */
+public interface ManagementServerHostStats {
+    Date getCollectionTime();
+
+    Date getSystemBootTime();
+
+    long getManagementServerHostId();
+
+    String getManagementServerHostUuid();
+
+    long getSessions();
+
+    double getCpuUtilization();
+
+    long getTotalJvmMemoryBytes();
+
+    double getFreeJvmMemoryBytes();
+
+    long getProcessJvmMemoryBytes();
+
+    long getJvmUptime();
+
+    long getJvmStartTime();
+
+    int getAvailableProcessors();
+
+    double getLoadAverage();
+
+    long getTotalInit();
+
+    long getTotalUsed();
+
+    long getMaxJvmMemoryBytes();
+
+    long getTotalCommitted();
+
+    long getPid();
+
+    String getJvmName();
+
+    String getJvmVendor();
+
+    String getJvmVersion();
+
+    String getOsDistribution();
+
+    int getAgentCount();
+
+    long getHeapMemoryUsed();
+
+    long getHeapMemoryTotal();
+
+    int getThreadsBlockedCount();
+
+    int getThreadsTotalCount();
+
+    int getThreadsDaemonCount();
+
+    int getThreadsRunnableCount();
+
+    int getThreadsTerminatedCount();
+
+    int getThreadsWaitingCount();
+
+    long getSystemMemoryTotal();
+
+    long getSystemMemoryFree();
+
+    long getSystemMemoryUsed();
+
+    long getSystemMemoryVirtualSize();
+
+    String getLogInfo();
+
+    /**
+     * @return in mega hertz
+     */
+    double getSystemTotalCpuCycles();
+
+    double[] getSystemLoadAverages();
+
+    long[] getSystemCyclesUsage();
+
+    boolean isDbLocal();
+
+    boolean isUsageLocal();
+
+    String getKernelVersion();
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 643060cee1..70ae181973 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -239,10 +239,17 @@ public class ApiConstants {
     public static final String IS_RECURSIVE = "isrecursive";
     public static final String ISO_FILTER = "isofilter";
     public static final String ISO_GUEST_OS_NONE = "None";
+    public static final String JAVA_DISTRIBUTION = "javadistribution";
+    public static final String JAVA_VERSION = "javaversion";
     public static final String JOB_ID = "jobid";
     public static final String JOB_STATUS = "jobstatus";
+    public static final String KEEPALIVE_ENABLED = "keepaliveenabled";
+    public static final String KERNEL_VERSION = "kernelversion";
     public static final String LABEL = "label";
     public static final String LASTNAME = "lastname";
+    public static final String LAST_BOOT = "lastboottime";
+    public static final String LAST_SERVER_START = "lastserverstart";
+    public static final String LAST_SERVER_STOP = "lastserverstop";
     public static final String LEVEL = "level";
     public static final String LENGTH = "length";
     public static final String LIMIT_CPU_USE = "limitcpuuse";
@@ -260,7 +267,6 @@ public class ApiConstants {
     public static final String MIGRATION_TYPE = "migrationtype";
     public static final String MEMORY = "memory";
     public static final String MODE = "mode";
-    public static final String KEEPALIVE_ENABLED = "keepaliveenabled";
     public static final String NAME = "name";
     public static final String METHOD_NAME = "methodname";
     public static final String NETWORK_DOMAIN = "networkdomain";
@@ -273,6 +279,7 @@ public class ApiConstants {
     public static final String NEW_END_IP = "newendip";
     public static final String NUM_RETRIES = "numretries";
     public static final String OFFER_HA = "offerha";
+    public static final String OS_DISTRIBUTION = "osdistribution";
     public static final String IS_SYSTEM_OFFERING = "issystem";
     public static final String IS_DEFAULT_USE = "defaultuse";
     public static final String OLD_FORMAT = "oldformat";
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
index efb7d878dd..0289e8f9e3 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
@@ -22,6 +22,9 @@ import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.EntityReference;
+import org.apache.cloudstack.management.ManagementServerHost.State;
+
+import java.util.Date;
 
 @EntityReference(value = ManagementServerHost.class)
 public class ManagementServerResponse extends BaseResponse {
@@ -35,12 +38,80 @@ public class ManagementServerResponse extends BaseResponse {
 
     @SerializedName(ApiConstants.STATE)
     @Param(description = "the state of the management server")
-    private ManagementServerHost.State state;
+    private State state;
 
     @SerializedName(ApiConstants.VERSION)
     @Param(description = "the version of the management server")
     private String version;
 
+    @SerializedName(ApiConstants.JAVA_DISTRIBUTION)
+    @Param(description = "the java distribution name running the management server process")
+    private String javaDistribution;
+
+    @SerializedName(ApiConstants.JAVA_VERSION)
+    @Param(description = "the version of the java distribution running the management server process")
+    private String javaVersion;
+
+    @SerializedName(ApiConstants.OS_DISTRIBUTION)
+    @Param(description = "the name of the OS distribution running on the management server")
+    private String osDistribution;
+
+    @SerializedName(ApiConstants.LAST_SERVER_START)
+    @Param(description = "the last time this Management Server was started")
+    private Date lastServerStart;
+
+    @SerializedName(ApiConstants.LAST_SERVER_STOP)
+    @Param(description = "the last time this Management Server was stopped")
+    private Date lastServerStop;
+
+    @SerializedName(ApiConstants.LAST_BOOT)
+    @Param(description = "the last time the host on which this Management Server runs was booted")
+    private Date lastBoot;
+
+    @SerializedName(ApiConstants.KERNEL_VERSION)
+    @Param(description = "the running OS kernel version for this Management Server")
+    private String kernelVersion;
+
+    public String getId() {
+        return this.id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public State getState() {
+        return state;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public String getJavaDistribution() {
+        return javaDistribution;
+    }
+
+    public String getOsDistribution() {
+        return osDistribution;
+    }
+
+    public Date getLastServerStart() {
+        return lastServerStart;
+    }
+
+    public Date getLastServerStop() {
+        return lastServerStop;
+    }
+
+    public Date getLastBoot() {
+        return lastBoot;
+    }
+
     public void setId(String id) {
         this.id = id;
     }
@@ -49,11 +120,39 @@ public class ManagementServerResponse extends BaseResponse {
         this.name = name;
     }
 
-    public void setState(ManagementServerHost.State state) {
+    public void setState(State state) {
         this.state = state;
     }
 
     public void setVersion(String version) {
         this.version = version;
     }
+
+    public void setJavaDistribution(String javaDistribution) {
+        this.javaDistribution = javaDistribution;
+    }
+
+    public void setJavaVersion(String javaVersion) {
+        this.javaVersion = javaVersion;
+    }
+
+    public void setOsDistribution(String osDistribution) {
+        this.osDistribution = osDistribution;
+    }
+
+    public void setLastServerStart(Date lastServerStart) {
+        this.lastServerStart = lastServerStart;
+    }
+
+    public void setLastServerStop(Date lastServerStop) {
+        this.lastServerStop = lastServerStop;
+    }
+
+    public void setLastBoot(Date lastBoot) {
+        this.lastBoot = lastBoot;
+    }
+
+    public void setKernelVersion(String kernelVersion) {
+        this.kernelVersion = kernelVersion;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/management/ManagementServerStatus.java b/api/src/main/java/org/apache/cloudstack/management/ManagementServerStatus.java
new file mode 100644
index 0000000000..bae8e35734
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/management/ManagementServerStatus.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.management;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface ManagementServerStatus extends InternalIdentity {
+    long getId();
+
+    String getMsId();
+
+    Date getLastJvmStart();
+
+    Date getLastJvmStop();
+
+    Date getLastSystemBoot();
+
+    String getOsDistribution();
+
+    String getJavaName();
+
+    String getJavaVersion();
+
+    Date getUpdated();
+
+    Date getCreated();
+
+    Date getRemoved();
+}
diff --git a/client/src/main/webapp/WEB-INF/web.xml b/client/src/main/webapp/WEB-INF/web.xml
index 03f7d15db6..9a3d8bc5b2 100644
--- a/client/src/main/webapp/WEB-INF/web.xml
+++ b/client/src/main/webapp/WEB-INF/web.xml
@@ -28,6 +28,9 @@
     <listener>
         <listener-class>org.apache.cloudstack.spring.module.web.CloudStackContextLoaderListener</listener-class>
     </listener>
+    <listener>
+        <listener-class>com.cloud.api.ApiSessionListener</listener-class>
+    </listener>
     <context-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:META-INF/cloudstack/webApplicationContext.xml</param-value>
diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/ConnectedAgentAttache.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/ConnectedAgentAttache.java
index f11a105b2a..82423205a6 100644
--- a/engine/orchestration/src/main/java/com/cloud/agent/manager/ConnectedAgentAttache.java
+++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/ConnectedAgentAttache.java
@@ -26,7 +26,7 @@ import com.cloud.host.Status;
 import com.cloud.utils.nio.Link;
 
 /**
- * ConnectedAgentAttache implements an direct connection to this management server.
+ * ConnectedAgentAttache implements a direct connection to this management server.
  */
 public class ConnectedAgentAttache extends AgentAttache {
     private static final Logger s_logger = Logger.getLogger(ConnectedAgentAttache.class);
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index 1ea65e26e7..54d4a5e9ca 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -142,4 +142,11 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
     HostVO findByName(String name);
 
     List<HostVO> listHostsWithActiveVMs(long offeringId);
+
+    /**
+     * Retrieves the number of hosts/agents this {@see ManagementServer} has responsibility over.
+     * @param msid the id of the {@see ManagementServer}
+     * @return the number of hosts/agents this {@see ManagementServer} has responsibility over
+     */
+    int countByMs(long msid);
 }
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 8b54c48bf5..8e1f8f470d 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -119,6 +119,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
     protected SearchBuilder<HostVO> UnmanagedApplianceSearch;
     protected SearchBuilder<HostVO> MaintenanceCountSearch;
     protected SearchBuilder<HostVO> HostTypeCountSearch;
+    protected SearchBuilder<HostVO> ResponsibleMsCountSearch;
     protected SearchBuilder<HostVO> HostTypeZoneCountSearch;
     protected SearchBuilder<HostVO> ClusterStatusSearch;
     protected SearchBuilder<HostVO> TypeNameZoneSearch;
@@ -179,6 +180,10 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
         HostTypeCountSearch.and("type", HostTypeCountSearch.entity().getType(), SearchCriteria.Op.EQ);
         HostTypeCountSearch.done();
 
+        ResponsibleMsCountSearch = createSearchBuilder();
+        ResponsibleMsCountSearch.and("managementServerId", ResponsibleMsCountSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ);
+        ResponsibleMsCountSearch.done();
+
         HostTypeZoneCountSearch = createSearchBuilder();
         HostTypeZoneCountSearch.and("type", HostTypeZoneCountSearch.entity().getType(), SearchCriteria.Op.EQ);
         HostTypeZoneCountSearch.and("dc", HostTypeZoneCountSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
@@ -1287,6 +1292,13 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
         }
     }
 
+    @Override
+    public int countByMs(long msid) {
+        SearchCriteria<HostVO> sc = ResponsibleMsCountSearch.create();
+        sc.setParameters("managementServerId", msid);
+        return getCount(sc);
+    }
+
     @Override
     public List<HostVO> listAllHostsByType(Host.Type type) {
         SearchCriteria<HostVO> sc = TypeSearch.create();
diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
index 2b0b56b468..d7b7d129f2 100644
--- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
+++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
@@ -118,6 +118,7 @@
   <bean id="inlineLoadBalancerNicMapDaoImpl" class="com.cloud.network.dao.InlineLoadBalancerNicMapDaoImpl" />
   <bean id="instanceGroupDaoImpl" class="com.cloud.vm.dao.InstanceGroupDaoImpl" />
   <bean id="instanceGroupJoinDaoImpl" class="com.cloud.api.query.dao.InstanceGroupJoinDaoImpl" />
+  <bean id="managementServerJoinDaoImpl" class="com.cloud.api.query.dao.ManagementServerJoinDaoImpl" />
   <bean id="instanceGroupVMMapDaoImpl" class="com.cloud.vm.dao.InstanceGroupVMMapDaoImpl" />
   <bean id="itWorkDaoImpl" class="com.cloud.vm.ItWorkDaoImpl" />
   <bean id="lBHealthCheckPolicyDaoImpl" class="com.cloud.network.dao.LBHealthCheckPolicyDaoImpl" />
@@ -128,6 +129,7 @@
   <bean id="loadBalancerCertMapDaoImpl" class="com.cloud.network.dao.LoadBalancerCertMapDaoImpl" />
   <bean id="managementServerHostDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostDaoImpl" />
   <bean id="managementServerHostPeerDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostPeerDaoImpl" />
+  <bean id="managementServerStatusDaoImpl" class="com.cloud.cluster.dao.ManagementServerStatusDaoImpl" />
   <bean id="networkAccountDaoImpl" class="com.cloud.network.dao.NetworkAccountDaoImpl" />
   <bean id="networkACLDaoImpl" class="com.cloud.network.vpc.dao.NetworkACLDaoImpl" />
   <bean id="networkACLItemDaoImpl" class="com.cloud.network.vpc.dao.NetworkACLItemDaoImpl" />
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql
index e6fd3708ca..7f82ecf475 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql
@@ -698,4 +698,86 @@ CREATE VIEW `cloud`.`domain_router_view` AS
             left join
         `cloud`.`async_job` ON async_job.instance_id = vm_instance.id
             and async_job.instance_type = 'DomainRouter'
-            and async_job.job_status = 0;
\ No newline at end of file
+            and async_job.job_status = 0;
+
+INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'listConfigurations', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule;
+INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'updateConfiguration', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule;
+
+-- table for network permissions
+CREATE TABLE  `cloud`.`network_permissions` (
+  `id` bigint unsigned NOT NULL auto_increment,
+  `network_id` bigint unsigned NOT NULL,
+  `account_id` bigint unsigned NOT NULL,
+  PRIMARY KEY  (`id`),
+  INDEX `i_network_permission_network_id`(`network_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT INTO `cloud`.`user_vm_details`(`vm_id`, `name`, `value`)
+    SELECT `user_vm_details`.`vm_id`, 'SSH.KeyPairNames', `ssh_keypairs`.`keypair_name`
+        FROM `cloud`.`user_vm_details`
+        INNER JOIN `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value
+        INNER JOIN `cloud`.`vm_instance` ON vm_instance.id = user_vm_details.vm_id
+        WHERE ssh_keypairs.account_id = vm_instance.account_id;
+
+ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `security_group_id` bigint unsigned DEFAULT NULL,
+ADD CONSTRAINT `fk_kubernetes_cluster__security_group_id` FOREIGN KEY `fk_kubernetes_cluster__security_group_id`(`security_group_id`) REFERENCES `security_group`(`id`) ON DELETE CASCADE;
+
+-- PR#5984 Create table to persist VM stats.
+DROP TABLE IF EXISTS `cloud`.`vm_stats`;
+CREATE TABLE `cloud`.`vm_stats` (
+  `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
+  `vm_id` bigint unsigned NOT NULL,
+  `mgmt_server_id` bigint unsigned NOT NULL,
+  `timestamp` datetime NOT NULL,
+  `vm_stats_data` text NOT NULL,
+  PRIMARY KEY (`id`)
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- PR#5984 Update name for global configuration vm.stats.increment.metrics
+Update configuration set name='vm.stats.increment.metrics' where name='vm.stats.increment.metrics.in.memory';
+--
+-- Management Server Status
+--
+ALTER TABLE `cloud`.`mshost` ADD CONSTRAINT `mshost_UUID` UNIQUE KEY (`uuid`);
+CREATE TABLE `cloud`.`mshost_status` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `ms_id` varchar(40) DEFAULT NULL COMMENT 'the uuid of the management server record',
+  `last_jvm_start` datetime DEFAULT NULL COMMENT 'the last start time for this MS',
+  `last_jvm_stop` datetime DEFAULT NULL COMMENT 'the last stop time for this MS',
+  `last_system_boot` datetime DEFAULT NULL COMMENT 'the last system boot time for the host of this MS',
+  `os_distribution` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'the name of the os type running on the host of this MS',
+  `java_name` varchar(64) DEFAULT NULL COMMENT 'the name of the java distribution running this MS',
+  `java_version` varchar(64) DEFAULT NULL COMMENT 'the version of the java distribution running this MS',
+  `updated` datetime DEFAULT NULL,
+  `created` datetime DEFAULT NULL,
+  `removed` datetime DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  CONSTRAINT `uc_ms_id` UNIQUE (`ms_id`),
+  CONSTRAINT `mshost_status_FK` FOREIGN KEY (`ms_id`) REFERENCES `mshost` (`uuid`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
+
+DROP VIEW IF EXISTS `cloud`.`mshost_view`;
+CREATE VIEW `cloud`.`mshost_view` AS
+select
+    `cloud`.`mshost`.`id` AS `id`,
+    `cloud`.`mshost`.`msid` AS `msid`,
+    `cloud`.`mshost`.`runid` AS `runid`,
+    `cloud`.`mshost`.`name` AS `name`,
+    `cloud`.`mshost`.`uuid` AS `uuid`,
+    `cloud`.`mshost`.`state` AS `state`,
+    `cloud`.`mshost`.`version` AS `version`,
+    `cloud`.`mshost`.`service_ip` AS `service_ip`,
+    `cloud`.`mshost`.`service_port` AS `service_port`,
+    `cloud`.`mshost`.`last_update` AS `last_update`,
+    `cloud`.`mshost`.`removed` AS `removed`,
+    `cloud`.`mshost`.`alert_count` AS `alert_count`,
+    `cloud`.`mshost_status`.`last_jvm_start` AS `last_jvm_start`,
+    `cloud`.`mshost_status`.`last_jvm_stop` AS `last_jvm_stop`,
+    `cloud`.`mshost_status`.`last_system_boot` AS `last_system_boot`,
+    `cloud`.`mshost_status`.`os_distribution` AS `os_distribution`,
+    `cloud`.`mshost_status`.`java_name` AS `java_name`,
+    `cloud`.`mshost_status`.`java_version` AS `java_version`
+from
+    (`cloud`.`mshost`
+left join `cloud`.`mshost_status` on
+    ((`cloud`.`mshost`.`uuid` = `cloud`.`mshost_status`.`ms_id`)));
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
index c4a800c795..1b1406c1ce 100644
--- a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
+++ b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java
@@ -21,6 +21,9 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 
 import com.cloud.utils.component.Manager;
 
+/**
+ * The definition of the framework for inter MS communication.
+ */
 public interface ClusterManager extends Manager {
     static final String ALERT_SUBJECT = "cluster-alert";
     final ConfigKey<Integer> HeartbeatInterval = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.interval", "management-server", "1500",
@@ -28,20 +31,26 @@ public interface ClusterManager extends Manager {
     final ConfigKey<Integer> HeartbeatThreshold = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.threshold", "management-server", "150000",
         "Threshold before self-fence the management server", true);
 
+    /**
+     * Adds a new packet to the incoming queue.
+     * @param pdu protocol data unit
+     */
     void OnReceiveClusterServicePdu(ClusterServicePdu pdu);
 
+    void publishStatus(String status);
+
     /**
-     * This executes
-     * @param strPeer
-     * @param agentId
-     * @param cmds
-     * @param stopOnError
-     * @return
+     * Creates and registers a PDU, notifies listeners, and waits on the PDU to be notified.
+     * @param strPeer destination
+     * @param agentId reference to a resource
+     * @param cmds any json string (probably containing encoded commands)
+     * @param stopOnError should the other side continue id an error is encountered
+     * @return json encoded answer from the far side
      */
     String execute(String strPeer, long agentId, String cmds, boolean stopOnError);
 
     /**
-     * Broadcast the command to all of the  management server nodes.
+     * Broadcast the command to all the management server nodes.
      * @param agentId agent id this broadcast is regarding
      * @param cmds commands to broadcast
      */
@@ -53,19 +62,44 @@ public interface ClusterManager extends Manager {
 
     void registerDispatcher(Dispatcher dispatcher);
 
+    /**
+     * Registers a listener for incoming status changes of ManagementServers.
+     *
+     * @param administrator the object administrating statuses
+     */
+    void registerStatusAdministrator(StatusAdministrator administrator);
+
     ManagementServerHost getPeer(String peerName);
 
+    /**
+     *
+     * @return A {code}Long.toString({code}{@see getManagementNodeId()}{code}){code} representation of the PID of the management server process.
+     */
     String getSelfPeerName();
 
     long getManagementNodeId();
 
+    /**
+     * determined by the time
+     * @return The start time of the management server as {code}System.currentTimeMillis(){code}.
+     */
     long getCurrentRunId();
 
-    public long getManagementRunId(long msId);
+    /**
+     * @return The other MS's id as derived from start time as stored in the db.
+     */
+    long getManagementRunId(long msId);
 
-    public interface Dispatcher {
+    interface Dispatcher {
         String getName();
 
         String dispatch(ClusterServicePdu pdu);
     }
+
+    /**
+     * The definition of what the client of {@see registerStatusAdministrator()} should implement.
+     */
+    interface StatusAdministrator {
+        String newStatus(ClusterServicePdu pdu);
+    }
 }
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java
index 600b25782f..289638fe22 100644
--- a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java
+++ b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java
@@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.cluster.dao.ManagementServerStatusDao;
 import org.apache.cloudstack.management.ManagementServerHost;
 import org.apache.cloudstack.framework.config.ConfigDepot;
 import org.apache.cloudstack.framework.config.ConfigKey;
@@ -97,10 +98,14 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
     @Inject
     private ManagementServerHostDao _mshostDao;
     @Inject
+    private ManagementServerStatusDao mshostStatusDao;
+    @Inject
     private ManagementServerHostPeerDao _mshostPeerDao;
 
     protected Dispatcher _dispatcher;
 
+    private StatusAdministrator statusAdministrator;
+
     //
     // pay attention to _mshostId and _msid
     // _mshostId is the primary key of management host table
@@ -139,6 +144,11 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
         _dispatcher = dispatcher;
     }
 
+    @Override
+    public void registerStatusAdministrator(final StatusAdministrator administrator) {
+        statusAdministrator = administrator;
+    }
+
     private ClusterServiceRequestPdu popRequestPdu(final long ackSequenceId) {
         synchronized (_outgoingPdusWaitingForAck) {
             if (_outgoingPdusWaitingForAck.get(ackSequenceId) != null) {
@@ -312,6 +322,12 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
                             } else {
                                 s_logger.warn("Original request has already been cancelled. pdu: " + pdu.getJsonPackage());
                             }
+                        } else if (pdu.getPduType() == ClusterServicePdu.PDU_TYPE_STATUS_UPDATE) {
+                            if (statusAdministrator == null) {
+                                s_logger.warn("No status administration to report a status update too.");
+                            } else {
+                                statusAdministrator.newStatus(pdu);
+                            }
                         } else {
                             String result = _dispatcher.dispatch(pdu);
                             if (result == null) {
@@ -385,6 +401,37 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
         addOutgoingClusterPdu(pdu);
     }
 
+    @Override
+    public void publishStatus(final String status) {
+        final Date cutTime = DateUtil.currentGMTTime();
+
+        final List<ManagementServerHostVO> peers = _mshostDao.getActiveList(new Date(cutTime.getTime() - HeartbeatThreshold.value()));
+        for (final ManagementServerHostVO peer : peers) {
+            final String peerName = Long.toString(peer.getMsid());
+            try {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Forwarding " + status + " to " + peer.getMsid());
+                }
+                sendStatus(peerName, status);
+            } catch (final Exception e) {
+                String msg = String.format("Caught exception while talking to %d", peer.getMsid());
+                s_logger.warn(msg);
+                s_logger.debug(msg, e);
+            }
+        }
+    }
+
+    public void sendStatus(final String strPeer, final String status) {
+        final ClusterServicePdu pdu = new ClusterServicePdu();
+        pdu.setSourcePeer(getSelfPeerName());
+        pdu.setDestPeer(strPeer);
+        pdu.setPduType(ClusterServicePdu.PDU_TYPE_STATUS_UPDATE);
+        pdu.setAgentId(0);
+        pdu.setJsonPackage(status);
+        pdu.setStopOnError(true);
+        addOutgoingClusterPdu(pdu);
+    }
+
     @Override
     public String execute(final String strPeer, final long agentId, final String cmds, final boolean stopOnError) {
         if (s_logger.isDebugEnabled()) {
@@ -1005,8 +1052,11 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
 
         if (_mshostId != null) {
             final ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId);
+            final ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid());
             mshost.setState(ManagementServerHost.State.Down);
+            mshostStatus.setLastJvmStop(new Date());
             _mshostDao.update(_mshostId, mshost);
+            mshostStatusDao.update(mshostStatus.getId(), mshostStatus);
         }
 
         _heartbeatScheduler.shutdownNow();
@@ -1141,7 +1191,10 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
                 return true;
             } catch (final IOException e) {
                 if (e instanceof ConnectException) {
-                    s_logger.error("Unable to ping management server at " + targetIp + ":" + mshost.getServicePort() + " due to ConnectException", e);
+                    s_logger.error("Unable to ping management server at " + targetIp + ":" + mshost.getServicePort() + " due to ConnectException");
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Unable to ping management server at " + targetIp + ":" + mshost.getServicePort() + " due to ConnectException", e);
+                    }
                     return false;
                 }
             } finally {
@@ -1200,5 +1253,4 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
             }
         }
     }
-
 }
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ClusterServicePdu.java b/framework/cluster/src/main/java/com/cloud/cluster/ClusterServicePdu.java
index 9f97469f78..ca5f1840ba 100644
--- a/framework/cluster/src/main/java/com/cloud/cluster/ClusterServicePdu.java
+++ b/framework/cluster/src/main/java/com/cloud/cluster/ClusterServicePdu.java
@@ -20,6 +20,7 @@ public class ClusterServicePdu {
     public final static int PDU_TYPE_MESSAGE = 0;
     public final static int PDU_TYPE_REQUEST = 1;
     public final static int PDU_TYPE_RESPONSE = 2;
+    public final static int PDU_TYPE_STATUS_UPDATE = 3;
 
     private long sequenceId;
     private long ackSequenceId;
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerStatusVO.java b/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerStatusVO.java
new file mode 100644
index 0000000000..6daeffe625
--- /dev/null
+++ b/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerStatusVO.java
@@ -0,0 +1,184 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.cluster;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.management.ManagementServerStatus;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+
+@Entity
+@Table(name = "mshost_status")
+public class ManagementServerStatusVO implements ManagementServerStatus {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+
+    @Column(name = "ms_id", nullable = false)
+    private String msId;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_jvm_start")
+    private Date lastJvmStart;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_jvm_stop")
+    private Date lastJvmStop;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_system_boot")
+    private Date lastSystemBoot;
+
+    @Column(name="os_distribution")
+    private String osDistribution;
+
+    @Column(name="java_name")
+    private String javaName;
+
+    @Column(name="java_version")
+    private String javaVersion;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "updated")
+    private Date updated;
+
+    @Column(name = GenericDao.CREATED_COLUMN)
+    private Date created;
+
+    @Column(name = GenericDao.REMOVED_COLUMN)
+    private Date removed;
+
+
+    public ManagementServerStatusVO() {
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getMsId() {
+        return msId;
+    }
+
+    public void setMsId(String msId) {
+        this.msId = msId;
+    }
+
+    @Override
+    public Date getLastJvmStart() {
+        return lastJvmStart;
+    }
+
+    public void setLastJvmStart(Date lastJvmStart) {
+        this.lastJvmStart = lastJvmStart;
+    }
+
+    @Override
+    public Date getLastJvmStop() {
+        return lastJvmStop;
+    }
+
+    public void setLastJvmStop(Date lastJvmStop) {
+        this.lastJvmStop = lastJvmStop;
+    }
+
+    @Override
+    public Date getLastSystemBoot() {
+        return lastSystemBoot;
+    }
+
+    public void setLastSystemBoot(Date lastSystemBoot) {
+        this.lastSystemBoot = lastSystemBoot;
+    }
+
+    @Override
+    public String getOsDistribution() {
+        return osDistribution;
+    }
+
+    public void setOsDistribution(String osDistribution) {
+        this.osDistribution = osDistribution;
+    }
+
+    @Override
+    public String getJavaName() {
+        return javaName;
+    }
+
+    public void setJavaName(String javaName) {
+        this.javaName = javaName;
+    }
+
+    @Override
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public void setJavaVersion(String javaVersion) {
+        this.javaVersion = javaVersion;
+    }
+
+    @Override
+    public Date getUpdated() {
+        return updated;
+    }
+
+    public void setUpdated(Date updated) {
+        this.updated = updated;
+    }
+
+    @Override
+    public Date getCreated() {
+        return created;
+    }
+
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+    @Override
+    public Date getRemoved() {
+        return removed;
+    }
+
+    public void setRemoved(Date removedTime) {
+        removed = removedTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ReflectionToStringBuilder(this, ToStringStyle.SIMPLE_STYLE).toString();
+    }
+}
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java
index 610826932a..be81b5fe04 100644
--- a/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java
+++ b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerHostDao.java
@@ -47,7 +47,12 @@ public interface ManagementServerHostDao extends GenericDao<ManagementServerHost
 
     List<ManagementServerHostVO> listBy(ManagementServerHost.State... states);
 
-    public List<Long> listOrphanMsids();
+    /**
+     * Lists msids for which hosts are orphaned, i.e. msids that hosts refer as their owning ms whilst no mshost entry exists with those msids
+     *
+     * @return a list of non existing MS IDs
+     */
+    List<Long> listOrphanMsids();
 
     ManagementServerHostVO findOneInUpState(Filter filter);
 }
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDao.java b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDao.java
new file mode 100644
index 0000000000..62f284386f
--- /dev/null
+++ b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDao.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.cluster.dao;
+
+import com.cloud.cluster.ManagementServerStatusVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface ManagementServerStatusDao extends GenericDao<ManagementServerStatusVO, Long> {
+    ManagementServerStatusVO findByMsId(String msId);
+}
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDaoImpl.java b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDaoImpl.java
new file mode 100644
index 0000000000..d40a104c2d
--- /dev/null
+++ b/framework/cluster/src/main/java/com/cloud/cluster/dao/ManagementServerStatusDaoImpl.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.cluster.dao;
+
+import com.cloud.cluster.ManagementServerStatusVO;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.List;
+
+public class ManagementServerStatusDaoImpl extends GenericDaoBase<ManagementServerStatusVO, Long> implements ManagementServerStatusDao {
+    private final SearchBuilder<ManagementServerStatusVO> MsIdSearch;
+
+    public ManagementServerStatusDaoImpl() {
+        MsIdSearch = createSearchBuilder();
+        MsIdSearch.and("msid", MsIdSearch.entity().getMsId(), SearchCriteria.Op.EQ);
+        MsIdSearch.done();
+    }
+
+    @Override
+    public ManagementServerStatusVO findByMsId(String msId) {
+        SearchCriteria<ManagementServerStatusVO> sc = MsIdSearch.create();
+        sc.setParameters("msid", msId);
+
+        List<ManagementServerStatusVO> allServerStats = listIncludingRemovedBy(sc);
+        if (CollectionUtils.isNotEmpty(allServerStats)) {
+            return allServerStats.get(0);
+        }
+
+        return null;
+    }
+}
diff --git a/framework/db/src/main/java/com/cloud/utils/db/DbUtil.java b/framework/db/src/main/java/com/cloud/utils/db/DbUtil.java
index f7f785062e..86a61bc69c 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/DbUtil.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/DbUtil.java
@@ -46,7 +46,7 @@ import org.apache.log4j.Logger;
 import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable;
 
 public class DbUtil {
-    protected final static Logger s_logger = Logger.getLogger(DbUtil.class);
+    protected final static Logger LOGGER = Logger.getLogger(DbUtil.class);
 
     private static Map<String, Connection> s_connectionForGlobalLocks = new HashMap<String, Connection>();
 
@@ -54,7 +54,7 @@ public class DbUtil {
         synchronized (s_connectionForGlobalLocks) {
             if (forLock) {
                 if (s_connectionForGlobalLocks.get(name) != null) {
-                    s_logger.error("Sanity check failed, global lock name " + name + " is already in use");
+                    LOGGER.error("Sanity check failed, global lock name " + name + " is already in use");
                     assert (false);
                 }
 
@@ -198,7 +198,7 @@ public class DbUtil {
     public static boolean getGlobalLock(String name, int timeoutSeconds) {
         Connection conn = getConnectionForGlobalLocks(name, true);
         if (conn == null) {
-            s_logger.error("Unable to acquire DB connection for global lock system");
+            LOGGER.error("Unable to acquire DB connection for global lock system");
             return false;
         }
 
@@ -211,15 +211,15 @@ public class DbUtil {
                     if (rs.getInt(1) > 0) {
                         return true;
                     } else {
-                        if (s_logger.isDebugEnabled())
-                            s_logger.debug("GET_LOCK() timed out on lock : " + name);
+                        if (LOGGER.isDebugEnabled())
+                            LOGGER.debug("GET_LOCK() timed out on lock : " + name);
                     }
                 }
             }
         } catch (SQLException e) {
-            s_logger.error("GET_LOCK() throws exception ", e);
+            LOGGER.error("GET_LOCK() throws exception ", e);
         } catch (Throwable e) {
-            s_logger.error("GET_LOCK() throws exception ", e);
+            LOGGER.error("GET_LOCK() throws exception ", e);
         }
 
         removeConnectionForGlobalLocks(name);
@@ -234,7 +234,7 @@ public class DbUtil {
     public static boolean releaseGlobalLock(String name) {
         try (Connection conn = getConnectionForGlobalLocks(name, false);) {
             if (conn == null) {
-                s_logger.error("Unable to acquire DB connection for global lock system");
+                LOGGER.error("Unable to acquire DB connection for global lock system");
                 assert (false);
                 return false;
             }
@@ -245,13 +245,13 @@ public class DbUtil {
                     if (rs != null && rs.first()) {
                         return rs.getInt(1) > 0;
                     }
-                    s_logger.error("releaseGlobalLock:RELEASE_LOCK() returns unexpected result");
+                    LOGGER.error("releaseGlobalLock:RELEASE_LOCK() returns unexpected result");
                 }
             }
         } catch (SQLException e) {
-            s_logger.error("RELEASE_LOCK() throws exception ", e);
+            LOGGER.error("RELEASE_LOCK() throws exception ", e);
         } catch (Throwable e) {
-            s_logger.error("RELEASE_LOCK() throws exception ", e);
+            LOGGER.error("RELEASE_LOCK() throws exception ", e);
         }
         return false;
     }
@@ -282,4 +282,24 @@ public class DbUtil {
         closeAutoCloseable(connection, "exception while close connection.");
     }
 
+    public static Map<String, String> getDbInfo(String type, String ... var) {
+        String vars = String.join(",", var);
+        Map<String, String> result = new HashMap<>();
+        String sql = String.format("SHOW %s WHERE FIND_IN_SET(Variable_name,?)",type);
+        try (TransactionLegacy txn = TransactionLegacy.open("metrics")) {
+            PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql);
+            pstmt.setString(1, vars);
+            final ResultSet rs = pstmt.executeQuery();
+            while (rs.next()) {
+                String variableName = rs.getString("Variable_name");
+                String value = rs.getString("value");
+                result.put(variableName, value);
+            }
+        } catch (SQLException e) {
+            LOGGER.error("failed to get the database status: " + e.getLocalizedMessage());
+            LOGGER.debug("failed to get the database status", e);
+        }
+        return result;
+    }
+
 }
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/web/CloudStackContextLoaderListener.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/web/CloudStackContextLoaderListener.java
index a90d6a5534..549c69d5da 100644
--- a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/web/CloudStackContextLoaderListener.java
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/web/CloudStackContextLoaderListener.java
@@ -47,6 +47,7 @@ public class CloudStackContextLoaderListener extends ContextLoaderListener {
 
     @Override
     public void contextInitialized(ServletContextEvent event) {
+        log.trace("context initialized");
         try {
             cloudStackContext = new CloudStackSpringContext();
             cloudStackContext.registerShutdownHook();
@@ -66,11 +67,11 @@ public class CloudStackContextLoaderListener extends ContextLoaderListener {
 
     @Override
     protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
+        log.trace("customize context");
         super.customizeContext(servletContext, applicationContext);
 
         String[] newLocations = cloudStackContext.getConfigLocationsForWeb(configuredParentName, applicationContext.getConfigLocations());
 
         applicationContext.setConfigLocations(newLocations);
     }
-
 }
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListDbMetricsCmd.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListDbMetricsCmd.java
new file mode 100644
index 0000000000..1100164dc4
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListDbMetricsCmd.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.DbMetricsResponse;
+
+import javax.inject.Inject;
+
+@APICommand(name=ListDbMetricsCmd.APINAME, description = "list the db hosts and statistics",
+        responseObject = DbMetricsResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+        responseView = ResponseObject.ResponseView.Full, since = "4.17.0", authorized = {RoleType.Admin})
+public class ListDbMetricsCmd extends BaseCmd {
+    public static final String APINAME = "listDbMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+        DbMetricsResponse response = metricsService.listDbMetrics();
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccountId();
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListMgmtsMetricsCmd.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListMgmtsMetricsCmd.java
new file mode 100644
index 0000000000..c3c9319bf9
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListMgmtsMetricsCmd.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.ManagementServerMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListMgmtsMetricsCmd.APINAME, description = "Lists Management Server metrics", responseObject = ManagementServerMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.17.0", authorized = {RoleType.Admin})
+public class ListMgmtsMetricsCmd  extends ListMgmtsCmd {
+    public static final String APINAME = "listManagementServersMetrics";
+
+    @Parameter(name = MetricConstants.SYSTEM, type = CommandType.BOOLEAN, entityType = ManagementServerMetricsResponse.class, description = "include system level stats")
+    private boolean system;
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        ListResponse<ManagementServerResponse> managementServers = _queryService.listManagementServers(this);
+        final List<ManagementServerMetricsResponse> metricsResponses = metricsService.listManagementServerMetrics(managementServers.getResponses());
+        ListResponse<ManagementServerMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, managementServers.getCount());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListUsageServerMetricsCmd.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListUsageServerMetricsCmd.java
new file mode 100644
index 0000000000..f39b8a4729
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListUsageServerMetricsCmd.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.UsageServerMetricsResponse;
+
+import javax.inject.Inject;
+
+@APICommand(name = ListUsageServerMetricsCmd.APINAME, description = "Lists Usage Server metrics", responseObject = UsageServerMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.17.0", authorized = {RoleType.Admin})
+public class ListUsageServerMetricsCmd  extends BaseCmd {
+    public static final String APINAME = "listUsageServerMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+        UsageServerMetricsResponse usageServerMetrics = metricsService.listUsageServerMetrics();
+        usageServerMetrics.setResponseName(getCommandName());
+        setResponseObject(usageServerMetrics);
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccountId();
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/MetricConstants.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/MetricConstants.java
new file mode 100644
index 0000000000..19a1cd4056
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/MetricConstants.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api;
+
+/**
+ * metric local api constants
+ */
+public interface MetricConstants {
+    String AGENT_COUNT = "agentcount";
+    String AVAILABLE_PROCESSORS = "availableprocessors";
+    String CONNECTIONS = "connections";
+    String DATABASE_IS_LOCAL = "dbislocal";
+    String DATABASE_LOAD_AVERAGES = "dbloadaverages";
+    String HEAP_MEMORY_USED = "heapmemoryused";
+    String HEAP_MEMORY_TOTAL = "heapmemorytotal";
+    String LAST_HEARTBEAT = "lastheartbeat";
+    String LAST_SUCCESSFUL_JOB = "lastsuccessfuljob";
+    String LOG_INFO = "loginfo";
+    String REPLICAS = "replicas";
+    String SESSIONS = "sessions";
+    String SYSTEM = "system";
+    String SYSTEM_CYCLES = "systemtotalcpucycles";
+    String SYSTEM_CYCLE_USAGE = "systemcycleusage";
+    String SYSTEM_LOAD_AVERAGES = "systemloadaverages";
+    String SYSTEM_MEMORY_FREE = "systemmemoryfree";
+    String SYSTEM_MEMORY_TOTAL = "systemmemorytotal";
+    String SYSTEM_MEMORY_USED = "systemmemoryused";
+    String SYSTEM_MEMORY_VIRTUALSIZE = "systemmemoryvirtualsize";
+    String THREADS_BLOCKED_COUNT = "threadsblockedcount";
+    String THREADS_DAEMON_COUNT = "threadsdaemoncount";
+    String THREADS_RUNNABLE_COUNT = "threadsrunnablecount";
+    String THREADS_TERMINATED_COUNT = "threadsteminatedcount";
+    String THREADS_TOTAL_COUNT = "threadstotalcount";
+    String THREADS_WAITING_COUNT = "threadswaitingcount";
+    String TLS_VERSIONS = "tlsversions";
+    String UPTIME = "uptime";
+    String USAGE_IS_LOCAL = "usageislocal";
+    String VERSION_COMMENT = "versioncomment";
+    String QUERIES = "queries";
+    String COLLECTION_TIME = "collectiontime";
+    String CPULOAD = "cpuload";
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsService.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsService.java
index 26c52f74b1..ee67fe86ba 100644
--- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsService.java
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsService.java
@@ -24,14 +24,18 @@ import org.apache.cloudstack.api.ListVMsUsageHistoryCmd;
 import org.apache.cloudstack.api.response.ClusterResponse;
 import org.apache.cloudstack.api.response.HostResponse;
 import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.response.ClusterMetricsResponse;
+import org.apache.cloudstack.response.DbMetricsResponse;
 import org.apache.cloudstack.response.HostMetricsResponse;
 import org.apache.cloudstack.response.InfrastructureResponse;
+import org.apache.cloudstack.response.ManagementServerMetricsResponse;
 import org.apache.cloudstack.response.StoragePoolMetricsResponse;
+import org.apache.cloudstack.response.UsageServerMetricsResponse;
 import org.apache.cloudstack.response.VmMetricsResponse;
 import org.apache.cloudstack.response.VmMetricsStatsResponse;
 import org.apache.cloudstack.response.VolumeMetricsResponse;
@@ -47,6 +51,10 @@ public interface MetricsService extends PluggableService {
     List<VmMetricsResponse> listVmMetrics(List<UserVmResponse> vmResponses);
     List<StoragePoolMetricsResponse> listStoragePoolMetrics(List<StoragePoolResponse> poolResponses);
     List<HostMetricsResponse> listHostMetrics(List<HostResponse> poolResponses);
+    List<ManagementServerMetricsResponse> listManagementServerMetrics(List<ManagementServerResponse> poolResponses);
     List<ClusterMetricsResponse> listClusterMetrics(Pair<List<ClusterResponse>, Integer> clusterResponses);
     List<ZoneMetricsResponse> listZoneMetrics(List<ZoneResponse> poolResponses);
+
+    UsageServerMetricsResponse listUsageServerMetrics();
+    DbMetricsResponse listDbMetrics();
 }
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
index df6dc09cf3..2968314938 100644
--- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java
@@ -24,14 +24,26 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.inject.Inject;
 
+import com.cloud.server.DbStatsCollection;
+import com.cloud.server.StatsCollector;
+import com.cloud.usage.UsageJobVO;
+import com.cloud.usage.dao.UsageJobDao;
+import com.cloud.utils.db.DbProperties;
+import com.cloud.utils.db.DbUtil;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.script.Script;
 import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.ListClustersMetricsCmd;
+import org.apache.cloudstack.api.ListDbMetricsCmd;
 import org.apache.cloudstack.api.ListHostsMetricsCmd;
 import org.apache.cloudstack.api.ListInfrastructureCmd;
+import org.apache.cloudstack.api.ListMgmtsMetricsCmd;
 import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd;
+import org.apache.cloudstack.api.ListUsageServerMetricsCmd;
 import org.apache.cloudstack.api.ListVMsMetricsCmd;
 import org.apache.cloudstack.api.ListVMsUsageHistoryCmd;
 import org.apache.cloudstack.api.ListVolumesMetricsCmd;
@@ -41,15 +53,21 @@ import org.apache.cloudstack.api.response.ClusterResponse;
 import org.apache.cloudstack.api.response.HostResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.api.response.StatsResponse;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.management.ManagementServerHost.State;
 import org.apache.cloudstack.response.ClusterMetricsResponse;
+import org.apache.cloudstack.response.DbMetricsResponse;
 import org.apache.cloudstack.response.HostMetricsResponse;
+import org.apache.cloudstack.response.HostMetricsSummary;
 import org.apache.cloudstack.response.InfrastructureResponse;
+import org.apache.cloudstack.response.ManagementServerMetricsResponse;
 import org.apache.cloudstack.response.StoragePoolMetricsResponse;
+import org.apache.cloudstack.response.UsageServerMetricsResponse;
 import org.apache.cloudstack.response.VmMetricsResponse;
 import org.apache.cloudstack.response.VmMetricsStatsResponse;
 import org.apache.cloudstack.response.VolumeMetricsResponse;
@@ -58,7 +76,6 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 
 import com.cloud.agent.api.VmStatsEntryBase;
 import com.cloud.alert.AlertManager;
@@ -86,6 +103,7 @@ import com.cloud.network.router.VirtualRouter;
 import com.cloud.org.Cluster;
 import com.cloud.org.Grouping;
 import com.cloud.org.Managed;
+import com.cloud.server.ManagementServerHostStats;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.utils.Pair;
@@ -101,8 +119,15 @@ import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.cloud.vm.dao.VmStatsDao;
 import com.google.gson.Gson;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.log4j.Logger;
+
+import static com.cloud.utils.NumbersUtil.toReadableSize;
 
 public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements MetricsService {
+    private static final Logger LOGGER = Logger.getLogger(MetricsServiceImpl.class);
 
     @Inject
     private DataCenterDao dataCenterDao;
@@ -134,6 +159,8 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
     protected UserVmDao userVmDao;
     @Inject
     protected VmStatsDao vmStatsDao;
+    @Inject
+    private UsageJobDao usageJobDao;
 
     private static Gson gson = new Gson();
 
@@ -141,16 +168,23 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
         super();
     }
 
-    private void updateHostMetrics(final Metrics metrics, final HostJoinVO host) {
-        metrics.incrTotalHosts();
-        metrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity());
-        metrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity());
+    private Double findRatioValue(final String value) {
+        if (value != null) {
+            return Double.valueOf(value);
+        }
+        return 1.0;
+    }
+
+    private void updateHostMetrics(final HostMetrics hostMetrics, final HostJoinVO host) {
+        hostMetrics.incrTotalHosts();
+        hostMetrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity());
+        hostMetrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity());
         final HostStats hostStats = ApiDBUtils.getHostStatistics(host.getId());
         if (hostStats != null) {
-            metrics.addCpuUsedPercentage(hostStats.getCpuUtilization());
-            metrics.addMemoryUsed((long) hostStats.getUsedMemory());
-            metrics.setMaximumCpuUsage(hostStats.getCpuUtilization());
-            metrics.setMaximumMemoryUsage((long) hostStats.getUsedMemory());
+            hostMetrics.addCpuUsedPercentage(hostStats.getCpuUtilization());
+            hostMetrics.addMemoryUsed((long) hostStats.getUsedMemory());
+            hostMetrics.setMaximumCpuUsage(hostStats.getCpuUtilization());
+            hostMetrics.setMaximumMemoryUsage((long) hostStats.getUsedMemory());
         }
     }
     /**
@@ -517,61 +551,152 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
             }
             final Long clusterId = cluster.getId();
 
-            // Thresholds
-            final Double cpuThreshold = AlertManager.CPUCapacityThreshold.valueIn(clusterId);
-            final Double memoryThreshold = AlertManager.MemoryCapacityThreshold.valueIn(clusterId);
-            final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
-            final Float memoryDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
-
             // CPU and memory capacities
             final CapacityDaoImpl.SummedCapacity cpuCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_CPU, null, clusterId);
             final CapacityDaoImpl.SummedCapacity memoryCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_MEMORY, null, clusterId);
-            final Metrics metrics = new Metrics(cpuCapacity, memoryCapacity);
+            final HostMetrics hostMetrics = new HostMetrics(cpuCapacity, memoryCapacity);
 
             for (final Host host: hostDao.findByClusterId(clusterId)) {
                 if (host == null || host.getType() != Host.Type.Routing) {
                     continue;
                 }
                 if (host.getStatus() == Status.Up) {
-                    metrics.incrUpResources();
+                    hostMetrics.incrUpResources();
                 }
-                metrics.incrTotalResources();
-                updateHostMetrics(metrics, hostJoinDao.findById(host.getId()));
+                hostMetrics.incrTotalResources();
+                updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId()));
             }
 
             metricsResponse.setState(clusterResponse.getAllocationState(), clusterResponse.getManagedState());
-            metricsResponse.setResources(metrics.getUpResources(), metrics.getTotalResources());
-            // CPU
-            metricsResponse.setCpuTotal(metrics.getTotalCpu());
-            metricsResponse.setCpuAllocated(metrics.getCpuAllocated(), metrics.getTotalCpu());
-            if (metrics.getCpuUsedPercentage() > 0L) {
-                metricsResponse.setCpuUsed(metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
-                metricsResponse.setCpuMaxDeviation(metrics.getMaximumCpuUsage(), metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
+            metricsResponse.setResources(hostMetrics.getUpResources(), hostMetrics.getTotalResources());
+            addHostCpuMetricsToResponse(metricsResponse, clusterId, hostMetrics);
+            addHostMemoryMetricsToResponse(metricsResponse, clusterId, hostMetrics);
+
+            metricsResponse.setHasAnnotation(clusterResponse.hasAnnotation());
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    private void addHostMemoryMetricsToResponse(HostMetricsSummary metricsResponse, Long clusterId, HostMetrics hostMetrics) {
+        final Long totalMemory = hostMetrics.getTotalMemory();
+        final Long memoryAllocated = hostMetrics.getMemoryAllocated();
+        final Long memoryUsed = hostMetrics.getMemoryUsed();
+        metricsResponse.setMemTotal(totalMemory);
+        metricsResponse.setMemAllocated(memoryAllocated, totalMemory);
+        if (memoryUsed > 0L) {
+            metricsResponse.setMemUsed(memoryUsed, totalMemory);
+            metricsResponse.setMemMaxDeviation(hostMetrics.getMaximumMemoryUsage(), memoryUsed, hostMetrics.getTotalHosts());
+        }
+        // thresholds
+        final Double memoryThreshold = (clusterId != null) ? AlertManager.MemoryCapacityThreshold.valueIn(clusterId) : AlertManager.MemoryCapacityThreshold.value();
+        final Float memoryDisableThreshold = (clusterId != null) ? DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId) : DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.value();
+        metricsResponse.setMemoryUsageThreshold(memoryUsed, totalMemory, memoryThreshold);
+        metricsResponse.setMemoryUsageDisableThreshold(memoryUsed, totalMemory, memoryDisableThreshold);
+        metricsResponse.setMemoryAllocatedThreshold(memoryAllocated, totalMemory, memoryThreshold);
+        metricsResponse.setMemoryAllocatedDisableThreshold(memoryAllocated, totalMemory, memoryDisableThreshold);
+
+    }
+
+    private void addHostCpuMetricsToResponse(HostMetricsSummary metricsResponse, Long clusterId, HostMetrics hostMetrics) {
+        Long totalHosts = hostMetrics.getTotalHosts();
+        Long totalCpu = hostMetrics.getTotalCpu();
+        Long cpuAllocated = hostMetrics.getCpuAllocated();
+        final Double cpuUsedPercentage = hostMetrics.getCpuUsedPercentage();
+
+        metricsResponse.setCpuTotal(totalCpu);
+        metricsResponse.setCpuAllocated(cpuAllocated, totalCpu);
+        if (cpuUsedPercentage > 0L) {
+            metricsResponse.setCpuUsed(cpuUsedPercentage, totalHosts);
+            metricsResponse.setCpuMaxDeviation(hostMetrics.getMaximumCpuUsage(), cpuUsedPercentage, totalHosts);
+        }
+        // thresholds
+        final Double cpuThreshold = (clusterId != null) ? AlertManager.CPUCapacityThreshold.valueIn(clusterId) : AlertManager.CPUCapacityThreshold.value();
+        final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
+        metricsResponse.setCpuUsageThreshold(cpuUsedPercentage, totalHosts, cpuThreshold);
+        metricsResponse.setCpuUsageDisableThreshold(cpuUsedPercentage, totalHosts, cpuDisableThreshold);
+        metricsResponse.setCpuAllocatedThreshold(cpuAllocated, totalCpu, cpuThreshold);
+        metricsResponse.setCpuAllocatedDisableThreshold(cpuAllocated, totalCpu, cpuDisableThreshold);
+    }
+
+
+    @Override
+    public List<ManagementServerMetricsResponse> listManagementServerMetrics(List<ManagementServerResponse> managementServerResponses) {
+        final List<ManagementServerMetricsResponse> metricsResponses = new ArrayList<>();
+        if(LOGGER.isDebugEnabled()) {
+            LOGGER.debug(String.format("Getting metrics for %d MS hosts.", managementServerResponses.size()));
+        }
+        for (final ManagementServerResponse managementServerResponse: managementServerResponses) {
+            if(LOGGER.isDebugEnabled()) {
+                LOGGER.debug(String.format("Processing metrics for MS hosts %s.", managementServerResponse.getId()));
             }
-            // Memory
-            metricsResponse.setMemTotal(metrics.getTotalMemory());
-            metricsResponse.setMemAllocated(metrics.getMemoryAllocated(), metrics.getTotalMemory());
-            if (metrics.getMemoryUsed() > 0L) {
-                metricsResponse.setMemUsed(metrics.getMemoryUsed(), metrics.getTotalMemory());
-                metricsResponse.setMemMaxDeviation(metrics.getMaximumMemoryUsage(), metrics.getMemoryUsed(), metrics.getTotalHosts());
+            ManagementServerMetricsResponse metricsResponse = new ManagementServerMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, managementServerResponse);
+                if (LOGGER.isTraceEnabled()) {
+                    LOGGER.trace(String.format("Bean copy result %s.", new ReflectionToStringBuilder(metricsResponse, ToStringStyle.SIMPLE_STYLE).toString()));
+                }
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate zone metrics response.");
             }
-            // CPU thresholds
-            metricsResponse.setCpuUsageThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuThreshold);
-            metricsResponse.setCpuUsageDisableThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuDisableThreshold);
-            metricsResponse.setCpuAllocatedThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuThreshold);
-            metricsResponse.setCpuAllocatedDisableThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuDisableThreshold);
-            // Memory thresholds
-            metricsResponse.setMemoryUsageThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryThreshold);
-            metricsResponse.setMemoryUsageDisableThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryDisableThreshold);
-            metricsResponse.setMemoryAllocatedThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryThreshold);
-            metricsResponse.setMemoryAllocatedDisableThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryDisableThreshold);
 
-            metricsResponse.setHasAnnotation(clusterResponse.hasAnnotation());
+            updateManagementServerMetrics(metricsResponse, managementServerResponse);
+
             metricsResponses.add(metricsResponse);
         }
         return metricsResponses;
     }
 
+    /**
+     * Get the transient/in memory data.
+     */
+    private void updateManagementServerMetrics(ManagementServerMetricsResponse metricsResponse, ManagementServerResponse managementServerResponse) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug(String.format("Getting stats for %s[%s]", managementServerResponse.getName(), managementServerResponse.getId()));
+        }
+        ManagementServerHostStats status = ApiDBUtils.getManagementServerHostStatistics(managementServerResponse.getId());
+        if (status == null ) {
+            LOGGER.info(String.format("No status object found for MS %s - %s.", managementServerResponse.getName(), managementServerResponse.getId()));
+        } else {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(String.format("Status object found for MS %s - %s.", managementServerResponse.getName(), new ReflectionToStringBuilder(status)));
+            }
+            if (StatsCollector.MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL.value() > 0) {
+                copyManagementServerStatusToResponse(metricsResponse, status);
+            }
+        }
+    }
+
+    private void copyManagementServerStatusToResponse(ManagementServerMetricsResponse metricsResponse, ManagementServerHostStats status) {
+        metricsResponse.setDbLocal(status.isDbLocal());
+        metricsResponse.setUsageLocal(status.isUsageLocal());
+        metricsResponse.setAvailableProcessors(status.getAvailableProcessors());
+        metricsResponse.setAgentCount(status.getAgentCount());
+        metricsResponse.setCollectionTime(status.getCollectionTime());
+        metricsResponse.setSessions(status.getSessions());
+        metricsResponse.setHeapMemoryUsed(status.getHeapMemoryUsed());
+        metricsResponse.setHeapMemoryTotal(status.getHeapMemoryTotal());
+        metricsResponse.setThreadsBlockedCount(status.getThreadsBlockedCount());
+        metricsResponse.setThreadsDaemonCount(status.getThreadsDaemonCount());
+        metricsResponse.setThreadsRunnableCount(status.getThreadsRunnableCount());
+        metricsResponse.setThreadsTerminatedCount(status.getThreadsTerminatedCount());
+        metricsResponse.setThreadsTotalCount(status.getThreadsTotalCount());
+        metricsResponse.setThreadsWaitingCount(status.getThreadsWaitingCount());
+        metricsResponse.setSystemMemoryTotal(toReadableSize(status.getSystemMemoryTotal()));
+        metricsResponse.setSystemMemoryFree(toReadableSize(status.getSystemMemoryFree()));
+// we are not adding metricsResponse.setSystemMemoryUsed(toReadableSize(status.getSystemMemoryUsed())); as the value is confusing and arguably wrong
+        metricsResponse.setSystemMemoryVirtualSize(toReadableSize(status.getSystemMemoryVirtualSize()));
+        metricsResponse.setLogInfo(status.getLogInfo());
+        metricsResponse.setSystemTotalCpuCycles(status.getSystemTotalCpuCycles());
+        metricsResponse.setSystemLoadAverages(status.getSystemLoadAverages());
+        long[] cycles = status.getSystemCyclesUsage();
+        metricsResponse.setSystemCycleUsage(cycles);
+        double currentLoad = 100.0 * (cycles[0] + cycles[1]) / (cycles[0] + cycles[1] + cycles[2]);
+        metricsResponse.setCpuLoad(currentLoad);
+        metricsResponse.setKernelVersion(status.getKernelVersion());
+    }
+
     @Override
     public List<ZoneMetricsResponse> listZoneMetrics(List<ZoneResponse> zoneResponses) {
         final List<ZoneMetricsResponse> metricsResponses = new ArrayList<>();
@@ -590,83 +715,173 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
             }
             final Long zoneId = zone.getId();
 
-            // Thresholds
-            final Double cpuThreshold = AlertManager.CPUCapacityThreshold.value();
-            final Double memoryThreshold = AlertManager.MemoryCapacityThreshold.value();
-            final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.value();
-            final Float memoryDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.value();
-
             // CPU and memory capacities
             final CapacityDaoImpl.SummedCapacity cpuCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_CPU, zoneId, null);
             final CapacityDaoImpl.SummedCapacity memoryCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_MEMORY, zoneId, null);
-            final Metrics metrics = new Metrics(cpuCapacity, memoryCapacity);
+            final HostMetrics hostMetrics = new HostMetrics(cpuCapacity, memoryCapacity);
 
             for (final Cluster cluster : clusterDao.listClustersByDcId(zoneId)) {
                 if (cluster == null) {
                     continue;
                 }
-                metrics.incrTotalResources();
+                hostMetrics.incrTotalResources();
                 if (cluster.getAllocationState() == Grouping.AllocationState.Enabled
                         && cluster.getManagedState() == Managed.ManagedState.Managed) {
-                    metrics.incrUpResources();
+                    hostMetrics.incrUpResources();
                 }
 
                 for (final Host host: hostDao.findByClusterId(cluster.getId())) {
                     if (host == null || host.getType() != Host.Type.Routing) {
                         continue;
                     }
-                    updateHostMetrics(metrics, hostJoinDao.findById(host.getId()));
+                    updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId()));
                 }
             }
 
             metricsResponse.setHasAnnotation(zoneResponse.hasAnnotation());
             metricsResponse.setState(zoneResponse.getAllocationState());
-            metricsResponse.setResource(metrics.getUpResources(), metrics.getTotalResources());
+            metricsResponse.setResource(hostMetrics.getUpResources(), hostMetrics.getTotalResources());
+
+            final Long totalHosts = hostMetrics.getTotalHosts();
             // CPU
-            metricsResponse.setCpuTotal(metrics.getTotalCpu());
-            metricsResponse.setCpuAllocated(metrics.getCpuAllocated(), metrics.getTotalCpu());
-            if (metrics.getCpuUsedPercentage() > 0L) {
-                metricsResponse.setCpuUsed(metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
-                metricsResponse.setCpuMaxDeviation(metrics.getMaximumCpuUsage(), metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
-            }
+            addHostCpuMetricsToResponse(metricsResponse, null, hostMetrics);
             // Memory
-            metricsResponse.setMemTotal(metrics.getTotalMemory());
-            metricsResponse.setMemAllocated(metrics.getMemoryAllocated(), metrics.getTotalMemory());
-            if (metrics.getMemoryUsed() > 0L) {
-                metricsResponse.setMemUsed(metrics.getMemoryUsed(), metrics.getTotalMemory());
-                metricsResponse.setMemMaxDeviation(metrics.getMaximumMemoryUsage(), metrics.getMemoryUsed(), metrics.getTotalHosts());
-            }
-            // CPU thresholds
-            metricsResponse.setCpuUsageThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuThreshold);
-            metricsResponse.setCpuUsageDisableThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuDisableThreshold);
-            metricsResponse.setCpuAllocatedThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuThreshold);
-            metricsResponse.setCpuAllocatedDisableThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuDisableThreshold);
-            // Memory thresholds
-            metricsResponse.setMemoryUsageThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryThreshold);
-            metricsResponse.setMemoryUsageDisableThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryDisableThreshold);
-            metricsResponse.setMemoryAllocatedThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryThreshold);
-            metricsResponse.setMemoryAllocatedDisableThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryDisableThreshold);
+            addHostMemoryMetricsToResponse(metricsResponse, null, hostMetrics);
 
             metricsResponses.add(metricsResponse);
         }
         return metricsResponses;
     }
 
+    @Override
+    public UsageServerMetricsResponse listUsageServerMetrics() {
+        UsageServerMetricsResponse response = new UsageServerMetricsResponse();
+        response.setCollectionTime(new Date());
+        TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
+        try {
+            response.setLastHeartbeat(usageJobDao.getLastHeartbeat());
+            response.setState(isUsageRunning() ? State.Up : State.Down);
+            UsageJobVO job = usageJobDao.getNextImmediateJob();
+            if (job == null) {
+                job = usageJobDao.getLastJob();
+            }
+            response.setHostname(job == null ? "N/A" : job.getHost());
+            response.setLastSuccessfulJob(new Date(usageJobDao.getLastJobSuccessDateMillis()));
+        } finally {
+            txn.close();
+            TransactionLegacy swap = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+            swap.close();
+        }
+        response.setObjectName("usageMetrics");
+        return response;
+    }
+
+    /**
+    Some TODOs left here
+          â—¦ State (Up / Down) , makes no sense (no db no cloudstack)
+          â—¦ Average Queries Per Second
+          â—¦ Buffer Pool Utilization (buffer pool is used to cache the table data in memory and is accessed repeatedly by queries without requiring any disk I/O).
+          â—¦ any other relevant stats (if useful) to the response from the sql status variables.
+     * @return the {@see DbMetricsResponse} containing the state of the DB
+     */
+    @Override
+    public DbMetricsResponse listDbMetrics() {
+        DbMetricsResponse response = new DbMetricsResponse();
+
+        response.setHostname(dbHostName());
+        response.setReplicas(dbReplicas());
+        getDynamicDataFromDB(response);
+        getStaticDataFromDB(response);
+
+        getQueryHistory(response);
+
+        if (LOGGER.isTraceEnabled()) {
+            LOGGER.trace(new ReflectionToStringBuilder(response));
+        }
+
+        response.setObjectName("dbMetrics");
+        return response;
+    }
+
+    private void getQueryHistory(DbMetricsResponse response) {
+        Map<String, Object> dbStats = ApiDBUtils.getDbStatistics();
+        if (dbStats != null) {
+            response.setQueries((Integer)dbStats.get(DbStatsCollection.queries));
+            response.setUptime((Integer)dbStats.get(DbStatsCollection.uptime));
+        }
+
+        List<Double> loadHistory = (List<Double>) dbStats.get(DbStatsCollection.loadAvarages);
+        double[] loadAverages = new double[loadHistory.size()];
+
+        int index = 0;
+        for (Double d : loadHistory) {
+            loadAverages[index++] = d;
+        }
+
+        response.setLoadAverages(loadAverages);
+        response.setCollectionTime((Date) dbStats.get(DbStatsCollection.collectionTime));
+
+    }
+
+    private void getStaticDataFromDB(DbMetricsResponse response) {
+        Map<String, String> vars = DbUtil.getDbInfo(DbStatsCollection.variables, DbStatsCollection.version, DbStatsCollection.versionComment);
+        response.setVersion(vars.get(DbStatsCollection.version));
+        response.setVersionComment(vars.get(DbStatsCollection.versionComment));
+    }
+
+    private void getDynamicDataFromDB(DbMetricsResponse response) {
+        Map<String, String> stats = DbUtil.getDbInfo(DbStatsCollection.status, DbStatsCollection.connections, DbStatsCollection.currentTlsVersion);
+        response.setConnections(Integer.parseInt(stats.get(DbStatsCollection.connections)));
+        response.setTlsVersions(stats.get(DbStatsCollection.currentTlsVersion));
+    }
+
+    private String dbHostName() {
+        Properties p =  DbProperties.getDbProperties();
+        return p.getProperty("db.cloud.host");
+    }
+
+    private String[] dbReplicas() {
+        Properties p =  DbProperties.getDbProperties();
+        return p.getProperty("db.cloud.replicas","").split(",");
+    }
+
+    /**
+     * Returns whether a local usage server is running.
+     * Note that this might not be the one actually doing the usage aggregation at this moment.
+     * @return true if the service is active.
+     */
+    protected boolean isUsageRunning() {
+        boolean local = false;
+        String usageStatus = Script.runSimpleBashScript("systemctl status cloudstack-usage | grep \"  Active:\"");
+
+        if (LOGGER.isTraceEnabled()) {
+            LOGGER.trace(String.format("The current usage status is: %s.", usageStatus));
+        }
+
+        if (StringUtils.isNotBlank(usageStatus)) {
+            local = usageStatus.contains("running");
+        }
+        return local;
+    }
+
     @Override
     public List<Class<?>> getCommands() {
         List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        cmdList.add(ListClustersMetricsCmd.class);
+        cmdList.add(ListDbMetricsCmd.class);
+        cmdList.add(ListHostsMetricsCmd.class);
         cmdList.add(ListInfrastructureCmd.class);
-        cmdList.add(ListVolumesMetricsCmd.class);
-        cmdList.add(ListVMsMetricsCmd.class);
+        cmdList.add(ListMgmtsMetricsCmd.class);
         cmdList.add(ListStoragePoolsMetricsCmd.class);
-        cmdList.add(ListHostsMetricsCmd.class);
-        cmdList.add(ListClustersMetricsCmd.class);
+        cmdList.add(ListUsageServerMetricsCmd.class);
+        cmdList.add(ListVMsMetricsCmd.class);
+        cmdList.add(ListVolumesMetricsCmd.class);
         cmdList.add(ListZonesMetricsCmd.class);
         cmdList.add(ListVMsUsageHistoryCmd.class);
         return cmdList;
     }
 
-    private class Metrics {
+    private class HostMetrics {
         // CPU metrics
         private Long totalCpu = 0L;
         private Long cpuAllocated = 0L;
@@ -682,7 +897,7 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
         private Long totalResources = 0L;
         private Long upResources = 0L;
 
-        public Metrics(final CapacityDaoImpl.SummedCapacity totalCpu, final CapacityDaoImpl.SummedCapacity totalMemory) {
+        public HostMetrics(final CapacityDaoImpl.SummedCapacity totalCpu, final CapacityDaoImpl.SummedCapacity totalMemory) {
             if (totalCpu != null) {
                 this.totalCpu = totalCpu.getTotalCapacity();
             }
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ClusterMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ClusterMetricsResponse.java
index a12ecd3b4f..18ea57d711 100644
--- a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ClusterMetricsResponse.java
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ClusterMetricsResponse.java
@@ -21,7 +21,7 @@ import com.cloud.serializer.Param;
 import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.api.response.ClusterResponse;
 
-public class ClusterMetricsResponse extends ClusterResponse {
+public class ClusterMetricsResponse extends ClusterResponse implements HostMetricsSummary {
     @SerializedName("state")
     @Param(description = "state of the cluster")
     private String state;
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/DbMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/DbMetricsResponse.java
new file mode 100644
index 0000000000..8abf5b585a
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/DbMetricsResponse.java
@@ -0,0 +1,107 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.MetricConstants;
+
+import java.util.Date;
+
+public class DbMetricsResponse extends BaseResponse {
+    @SerializedName(MetricConstants.COLLECTION_TIME)
+    @Param(description = "the time these statistics were collected")
+    private Date collectionTime;
+
+    @SerializedName(ApiConstants.HOST_NAME)
+    @Param(description = "the name of the active usage server")
+    private String hostname;
+
+    @SerializedName(MetricConstants.REPLICAS)
+    @Param(description = "the state of the usage server")
+    private String[] replicas;
+
+    @SerializedName(MetricConstants.CONNECTIONS)
+    @Param(description = "the number of connections to the DB")
+    private int connections;
+
+    @SerializedName(MetricConstants.UPTIME)
+    @Param(description = "the uptime of the DB in seconds")
+    private int uptime;
+
+    @SerializedName(MetricConstants.TLS_VERSIONS)
+    @Param(description = "the tls versions currently in use (accepted) by the DB")
+    private String tlsVersions;
+
+    @SerializedName(ApiConstants.VERSION)
+    @Param(description = "the version of the currently running DB")
+    private String version;
+
+    @SerializedName(MetricConstants.VERSION_COMMENT)
+    @Param(description = "the version of the currently running DB")
+    private String versionComment;
+
+    @SerializedName(MetricConstants.QUERIES)
+    @Param(description = "the number of queries performed on the DB")
+    private int queries;
+
+    @SerializedName(MetricConstants.DATABASE_LOAD_AVERAGES)
+    @Param(description = "the last measured load averages on the DB")
+    private double[] loadAverages;
+
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setReplicas(String[] replicas) {
+        this.replicas = replicas;
+    }
+
+    public void setConnections(int connections) {
+        this.connections = connections;
+    }
+
+    public void setUptime(int uptime) {
+        this.uptime = uptime;
+    }
+
+    public void setTlsVersions(String tlsVersions) {
+        this.tlsVersions = tlsVersions;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public void setVersionComment(String versionComment) {
+        this.versionComment = versionComment;
+    }
+
+    public void setQueries(int queries) {
+        this.queries = queries;
+    }
+
+    public void setLoadAverages(double []  loadAverages) {
+        this.loadAverages = loadAverages;
+    }
+
+    public void setCollectionTime(Date collectionTime) {
+        this.collectionTime = collectionTime;
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsSummary.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsSummary.java
new file mode 100644
index 0000000000..e3610c8f1a
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsSummary.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.response;
+
+public interface HostMetricsSummary {
+    void setCpuTotal(Long totalCpu);
+
+    void setCpuAllocated(Long cpuAllocated, Long totalCpu);
+
+    void setCpuUsed(Double cpuUsedPercentage, Long totalHosts);
+
+    void setCpuMaxDeviation(Double maximumCpuUsage, Double cpuUsedPercentage, Long totalHosts);
+
+    void setCpuUsageThreshold(Double cpuUsedPercentage, Long totalHosts, Double cpuThreshold);
+
+    void setCpuUsageDisableThreshold(Double cpuUsedPercentage, Long totalHosts, Float cpuDisableThreshold);
+
+    void setCpuAllocatedThreshold(Long cpuAllocated, Long totalCpu, Double cpuThreshold);
+
+    void setCpuAllocatedDisableThreshold(Long cpuAllocated, Long totalCpu, Float cpuDisableThreshold);
+
+    void setMemTotal(Long totalMemory);
+
+    void setMemAllocated(Long memoryAllocated, Long totalMemory);
+
+    void setMemUsed(Long memoryUsed, Long totalMemory);
+
+    void setMemMaxDeviation(Long maximumMemoryUsage, Long memoryUsed, Long totalHosts);
+
+    void setMemoryUsageThreshold(Long memoryUsed, Long totalMemory, Double memoryThreshold);
+
+    void setMemoryUsageDisableThreshold(Long memoryUsed, Long totalMemory, Float memoryDisableThreshold);
+
+    void setMemoryAllocatedThreshold(Long memoryAllocated, Long totalMemory, Double memoryThreshold);
+
+    void setMemoryAllocatedDisableThreshold(Long memoryAllocated, Long totalMemory, Float memoryDisableThreshold);
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java
new file mode 100644
index 0000000000..ae0f57b967
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java
@@ -0,0 +1,211 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.MetricConstants;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
+
+import java.util.Date;
+
+public class ManagementServerMetricsResponse extends ManagementServerResponse {
+
+    @SerializedName(MetricConstants.AVAILABLE_PROCESSORS)
+    @Param(description = "the number of processors available to the JVM")
+    private Integer availableProcessors;
+
+    @SerializedName(MetricConstants.AGENT_COUNT)
+    @Param(description = "the number of agents this Management Server is responsible for")
+    private Integer agentCount;
+
+    @SerializedName(MetricConstants.SESSIONS)
+    @Param(description = "the number of client sessions active on this Management Server")
+    private Long sessions;
+
+    @SerializedName(MetricConstants.HEAP_MEMORY_USED)
+    @Param(description = "the amount of memory used by this Management Server")
+    private Long heapMemoryUsed;
+
+    @SerializedName(MetricConstants.HEAP_MEMORY_TOTAL)
+    @Param(description = "the amount of memory allocated to this Management Server")
+    private Long heapMemoryTotal;
+
+    @SerializedName(MetricConstants.THREADS_BLOCKED_COUNT)
+    @Param(description = "The number of blocked threads")
+    private Integer threadsBlockedCount;
+
+    @SerializedName(MetricConstants.THREADS_DAEMON_COUNT)
+    @Param(description = "The number of daemon threads")
+    private Integer threadsDaemonCount;
+
+    @SerializedName(MetricConstants.THREADS_RUNNABLE_COUNT)
+    @Param(description = "The number of runnable threads")
+    private Integer threadsRunnableCount;
+
+    @SerializedName(MetricConstants.THREADS_TERMINATED_COUNT)
+    @Param(description = "The number of terminated threads")
+    private Integer threadsTerminatedCount;
+
+    @SerializedName(MetricConstants.THREADS_TOTAL_COUNT)
+    @Param(description = "The number of threads")
+    private Integer threadsTotalCount;
+
+    @SerializedName(MetricConstants.THREADS_WAITING_COUNT)
+    @Param(description = "The number of waiting threads")
+    private Integer threadsWaitingCount;
+
+    @SerializedName(MetricConstants.SYSTEM_MEMORY_TOTAL)
+    @Param(description = "Total system memory")
+    private String systemMemoryTotal;
+
+    @SerializedName(MetricConstants.SYSTEM_MEMORY_FREE)
+    @Param(description = "Free system memory")
+    private String systemMemoryFree;
+
+    @SerializedName(MetricConstants.SYSTEM_MEMORY_USED)
+    @Param(description = "Amount of memory used")
+    private String systemMemoryUsed;
+
+    @SerializedName(MetricConstants.SYSTEM_MEMORY_VIRTUALSIZE)
+    @Param(description = "Virtual size of the fully loaded process")
+    private String systemMemoryVirtualSize;
+
+    @SerializedName(MetricConstants.LOG_INFO)
+    @Param(description = "the log files and their usage on disk")
+    private String logInfo;
+
+    @SerializedName(MetricConstants.SYSTEM_CYCLES)
+    @Param(description = "the total system cpu capacity")
+    private Double systemTotalCpuCycles;
+
+    @SerializedName(MetricConstants.SYSTEM_LOAD_AVERAGES)
+    @Param(description = "the load averages for 1 5 and 15 minutes")
+    private double[] systemLoadAverages;
+
+    @SerializedName(MetricConstants.SYSTEM_CYCLE_USAGE)
+    @Param(description = "the system load for user, and system processes and the system idle cycles")
+    private long[] systemCycleUsage;
+
+    @SerializedName(MetricConstants.DATABASE_IS_LOCAL)
+    @Param(description = "the system is running against a local database")
+    private Boolean dbLocal;
+
+    @SerializedName(MetricConstants.USAGE_IS_LOCAL)
+    @Param(description = "the system has a usage server running locally")
+    private Boolean usageLocal;
+
+    @SerializedName(MetricConstants.CPULOAD)
+    @Param(description = "the current cpu load")
+    private String cpuLoad;
+
+    @SerializedName(MetricConstants.COLLECTION_TIME)
+    @Param(description = "the time these statistics were collected")
+    private Date collectionTime;
+
+    public void setAvailableProcessors(int availableProcessors) {
+        this.availableProcessors = availableProcessors;
+    }
+
+    public void setAgentCount(int agentCount) {
+        this.agentCount = agentCount;
+    }
+
+    public void setSessions(long sessions) {
+        this.sessions = sessions;
+    }
+
+    public void setHeapMemoryUsed(long heapMemoryUsed) {
+        this.heapMemoryUsed = heapMemoryUsed;
+    }
+
+    public void setHeapMemoryTotal(long heapMemoryTotal) {
+        this.heapMemoryTotal = heapMemoryTotal;
+    }
+
+    public void setThreadsBlockedCount(int threadsBlockedCount) {
+        this.threadsBlockedCount = threadsBlockedCount;
+    }
+
+    public void setThreadsDaemonCount(int threadsDaemonCount) {
+        this.threadsDaemonCount = threadsDaemonCount;
+    }
+
+    public void setThreadsRunnableCount(int threadsRunnableCount) {
+        this.threadsRunnableCount = threadsRunnableCount;
+    }
+
+    public void setThreadsTerminatedCount(int threadsTerminatedCount) {
+        this.threadsTerminatedCount = threadsTerminatedCount;
+    }
+
+    public void setThreadsTotalCount(int threadsTotalCount) {
+        this.threadsTotalCount = threadsTotalCount;
+    }
+
+    public void setThreadsWaitingCount(int threadsWaitingCount) {
+        this.threadsWaitingCount = threadsWaitingCount;
+    }
+
+    public void setSystemMemoryTotal(String systemMemoryTotal) {
+        this.systemMemoryTotal = systemMemoryTotal;
+    }
+
+    public void setSystemMemoryFree(String systemMemoryFree) {
+        this.systemMemoryFree = systemMemoryFree;
+    }
+
+    public void setSystemMemoryUsed(String systemMemoryUsed) {
+        this.systemMemoryUsed = systemMemoryUsed;
+    }
+
+    public void setSystemMemoryVirtualSize(String systemMemoryVirtualSize) {
+        this.systemMemoryVirtualSize = systemMemoryVirtualSize;
+    }
+
+    public void setLogInfo(String logInfo) {
+        this.logInfo = logInfo;
+    }
+
+    public void setSystemTotalCpuCycles(double systemTotalCpuCycles) {
+        this.systemTotalCpuCycles = systemTotalCpuCycles;
+    }
+
+    public void setSystemLoadAverages(double[] systemLoadAverages) {
+        this.systemLoadAverages = systemLoadAverages;
+    }
+
+    public void setSystemCycleUsage(long[] systemCycleUsage) {
+        this.systemCycleUsage = systemCycleUsage;
+    }
+
+    public void setDbLocal(boolean dbLocal) {
+        this.dbLocal = dbLocal;
+    }
+
+    public void setUsageLocal(boolean usageLocal) {
+        this.usageLocal = usageLocal;
+    }
+
+    public void setCollectionTime(Date collectionTime) {
+        this.collectionTime = collectionTime;
+    }
+
+    public void setCpuLoad(double cpuLoad) {
+        this.cpuLoad = String.format("%.2f %%",cpuLoad);
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/UsageServerMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/UsageServerMetricsResponse.java
new file mode 100644
index 0000000000..845d223ded
--- /dev/null
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/UsageServerMetricsResponse.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.MetricConstants;
+import org.apache.cloudstack.management.ManagementServerHost.State;
+
+import java.util.Date;
+
+public class UsageServerMetricsResponse  extends BaseResponse {
+    @SerializedName(MetricConstants.COLLECTION_TIME)
+    @Param(description = "the time these statistics were collected")
+    private Date collectionTime;
+
+    @SerializedName(ApiConstants.HOST_NAME)
+    @Param(description = "the name of the active usage server")
+    private String hostname;
+
+    @SerializedName(ApiConstants.STATE)
+    @Param(description = "the state of the usage server")
+    private State state;
+
+    @SerializedName(MetricConstants.LAST_HEARTBEAT)
+    @Param(description = "the last time this Usage Server checked for jobs")
+    private Date lastHeartbeat;
+
+    @SerializedName(MetricConstants.LAST_SUCCESSFUL_JOB)
+    @Param(description = "the last time a usage job successfully completed")
+    private Date lastSuccessfulJob;
+
+    public void setCollectionTime(Date collectionTime) {
+        this.collectionTime = collectionTime;
+    }
+
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setState(State state) {
+        this.state = state;
+    }
+
+    public void setLastHeartbeat(Date lastHeartbeat) {
+        this.lastHeartbeat = lastHeartbeat;
+    }
+
+    public void setLastSuccessfulJob(Date lastSuccessfulJob) {
+        this.lastSuccessfulJob = lastSuccessfulJob;
+    }
+}
diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ZoneMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ZoneMetricsResponse.java
index b3c1f86a68..c6bdda3de3 100644
--- a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ZoneMetricsResponse.java
+++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ZoneMetricsResponse.java
@@ -21,7 +21,7 @@ import com.cloud.serializer.Param;
 import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.api.response.ZoneResponse;
 
-public class ZoneMetricsResponse extends ZoneResponse {
+public class ZoneMetricsResponse extends ZoneResponse implements HostMetricsSummary {
     @SerializedName("state")
     @Param(description = "state of the cluster")
     private String state;
diff --git a/plugins/metrics/src/test/java/org/apache/cloudstack/metrics/MetricsServiceImplTest.java b/plugins/metrics/src/test/java/org/apache/cloudstack/metrics/MetricsServiceImplTest.java
index 59ebaf7525..ddc4d8b30b 100644
--- a/plugins/metrics/src/test/java/org/apache/cloudstack/metrics/MetricsServiceImplTest.java
+++ b/plugins/metrics/src/test/java/org/apache/cloudstack/metrics/MetricsServiceImplTest.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.metrics;
 
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -47,6 +48,7 @@ import com.cloud.vm.VmStatsVO;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VmStatsDao;
 
+
 @RunWith(MockitoJUnitRunner.class)
 public class MetricsServiceImplTest {
 
diff --git a/server/pom.xml b/server/pom.xml
index 3f44277a71..ba2247713e 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -170,6 +170,16 @@
             <groupId>org.influxdb</groupId>
             <artifactId>influxdb-java</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.codahale.metrics</groupId>
+            <artifactId>metrics-core</artifactId>
+            <version>3.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.codahale.metrics</groupId>
+            <artifactId>metrics-jvm</artifactId>
+            <version>3.0.2</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java
index 221202f7a9..bd11136b63 100644
--- a/server/src/main/java/com/cloud/api/ApiDBUtils.java
+++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java
@@ -189,6 +189,7 @@ import com.cloud.resource.ResourceManager;
 import com.cloud.resource.icon.ResourceIconVO;
 import com.cloud.resource.icon.dao.ResourceIconDao;
 import com.cloud.server.ManagementServer;
+import com.cloud.server.ManagementServerHostStats;
 import com.cloud.server.ResourceIcon;
 import com.cloud.server.ResourceManagerUtil;
 import com.cloud.server.ResourceMetaDataService;
@@ -990,6 +991,14 @@ public class ApiDBUtils {
         return s_statsCollector.getHostStats(hostId);
     }
 
+    public static ManagementServerHostStats getManagementServerHostStatistics(String mgmtSrvrUuid) {
+        return s_statsCollector.getManagementServerHostStats(mgmtSrvrUuid);
+    }
+
+    public static Map<String,Object> getDbStatistics() {
+        return s_statsCollector.getDbStats();
+    }
+
     public static StorageStats getStoragePoolStatistics(long id) {
         return s_statsCollector.getStoragePoolStats(id);
     }
diff --git a/server/src/main/java/com/cloud/api/ApiSessionListener.java b/server/src/main/java/com/cloud/api/ApiSessionListener.java
new file mode 100644
index 0000000000..6bb853d76c
--- /dev/null
+++ b/server/src/main/java/com/cloud/api/ApiSessionListener.java
@@ -0,0 +1,90 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api;
+
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.annotation.WebListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+import org.apache.log4j.Logger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@WebListener
+public class ApiSessionListener implements HttpSessionListener, ServletRequestListener {
+    public static final Logger LOGGER = Logger.getLogger(ApiSessionListener.class.getName());
+    private static final String ATTRIBUTE_NAME = "SessionCounter";
+    private static Map<HttpSession, Object> sessions = new ConcurrentHashMap<>();
+    private static long sessionCount;
+
+    public ApiSessionListener() {
+        sessionCount = 0;
+    }
+
+    /**
+     * @return the internal adminstered session count
+     */
+    public static long getSessionCount() {
+        return sessionCount;
+    }
+
+    /**
+     * @return the size of the internal {@see Map} of sessions
+     */
+    public static long getNumberOfSessions() {
+        return sessions.size();
+    }
+    public void sessionCreated(HttpSessionEvent event) {
+        LOGGER.debug("Session created by Id : " + event.getSession().getId() + " , session: " + event.getSession().toString() + " , source: " + event.getSource().toString() + " , event: " + event.toString());
+        synchronized (this) {
+            HttpSession session = event.getSession();
+            sessions.put(session, event.getSource());
+            sessionCount++;
+        }
+        LOGGER.debug("Sessions count: " + sessions);
+    }
+    public void sessionDestroyed(HttpSessionEvent event) {
+        LOGGER.debug("Session destroyed by Id : " + event.getSession().getId() + " , session: " + event.getSession().toString() + " , source: " + event.getSource().toString() + " , event: " + event.toString());
+        synchronized (this) {
+            sessionCount--;
+            sessions.remove(event.getSession());
+        }
+        LOGGER.debug("Sessions count: " + sessions);
+    }
+
+    @Override
+    public void requestDestroyed(ServletRequestEvent event) {
+        LOGGER.debug("request destroyed");
+    }
+
+    @Override
+    public void requestInitialized(ServletRequestEvent event) {
+        LOGGER.debug("request initialized");
+        HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
+        HttpSession session = request.getSession();
+        if (session.isNew()) {
+            synchronized (this) {
+                // replace the source object for the address
+                sessions.put(session, request.getRemoteAddr());
+            }
+        }
+    }
+}
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index 6a78b32dcb..4bc5ccd56d 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -119,14 +119,12 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.query.QueryService;
 import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
@@ -142,6 +140,7 @@ import com.cloud.api.query.dao.HostJoinDao;
 import com.cloud.api.query.dao.HostTagDao;
 import com.cloud.api.query.dao.ImageStoreJoinDao;
 import com.cloud.api.query.dao.InstanceGroupJoinDao;
+import com.cloud.api.query.dao.ManagementServerJoinDao;
 import com.cloud.api.query.dao.ProjectAccountJoinDao;
 import com.cloud.api.query.dao.ProjectInvitationJoinDao;
 import com.cloud.api.query.dao.ProjectJoinDao;
@@ -165,6 +164,7 @@ import com.cloud.api.query.vo.HostJoinVO;
 import com.cloud.api.query.vo.HostTagVO;
 import com.cloud.api.query.vo.ImageStoreJoinVO;
 import com.cloud.api.query.vo.InstanceGroupJoinVO;
+import com.cloud.api.query.vo.ManagementServerJoinVO;
 import com.cloud.api.query.vo.ProjectAccountJoinVO;
 import com.cloud.api.query.vo.ProjectInvitationJoinVO;
 import com.cloud.api.query.vo.ProjectJoinVO;
@@ -176,8 +176,6 @@ import com.cloud.api.query.vo.TemplateJoinVO;
 import com.cloud.api.query.vo.UserAccountJoinVO;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.api.query.vo.VolumeJoinVO;
-import com.cloud.cluster.ManagementServerHostVO;
-import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.dc.DedicatedResourceVO;
 import com.cloud.dc.dao.DedicatedResourceDao;
 import com.cloud.domain.Domain;
@@ -213,7 +211,6 @@ import com.cloud.server.ResourceManagerUtil;
 import com.cloud.server.ResourceMetaDataService;
 import com.cloud.server.ResourceTag;
 import com.cloud.server.ResourceTag.ResourceObjectType;
-import com.cloud.server.TaggedResourceService;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.service.dao.ServiceOfferingDetailsDao;
@@ -228,7 +225,6 @@ import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.dao.StoragePoolTagsDao;
 import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateDetailsDao;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.tags.ResourceTagVO;
@@ -337,9 +333,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
     @Inject
     private AccountDao _accountDao;
 
-    @Inject
-    private ConfigurationDao _configDao;
-
     @Inject
     private AccountJoinDao _accountJoinDao;
 
@@ -396,9 +389,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
     @Inject
     private ResourceMetaDataService _resourceMetaDataMgr;
 
-    @Inject
-    private TaggedResourceService _taggedResourceMgr;
-
     @Inject
     private ResourceManagerUtil resourceManagerUtil;
 
@@ -424,10 +414,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
     private DataStoreManager dataStoreManager;
 
     @Inject
-    ManagementServerHostDao managementServerHostDao;
-
-    @Inject
-    VMTemplateDetailsDao vmTemplateDetailsDao;
+    ManagementServerJoinDao managementServerJoinDao;
 
     @Inject
     public VpcVirtualNetworkApplianceService routerService;
@@ -438,9 +425,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
     @Inject
     private RouterHealthCheckResultDao routerHealthCheckResultDao;
 
-    @Inject
-    private TemplateDataStoreDao templateDataStoreDao;
-
     @Inject
     private PrimaryDataStoreDao _storagePoolDao;
 
@@ -4310,10 +4294,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
     @Override
     public ListResponse<ManagementServerResponse> listManagementServers(ListMgmtsCmd cmd) {
         ListResponse<ManagementServerResponse> response = new ListResponse<>();
-        Pair<List<ManagementServerHostVO>, Integer> result = listManagementServersInternal(cmd);
+        Pair<List<ManagementServerJoinVO>, Integer> result = listManagementServersInternal(cmd);
         List<ManagementServerResponse> hostResponses = new ArrayList<>();
 
-        for (ManagementServerHostVO host : result.first()) {
+        for (ManagementServerJoinVO host : result.first()) {
             ManagementServerResponse hostResponse = createManagementServerResponse(host);
             hostResponses.add(hostResponse);
         }
@@ -4322,27 +4306,33 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
         return response;
     }
 
-    protected Pair<List<ManagementServerHostVO>, Integer> listManagementServersInternal(ListMgmtsCmd cmd) {
+    protected Pair<List<ManagementServerJoinVO>, Integer> listManagementServersInternal(ListMgmtsCmd cmd) {
         Long id = cmd.getId();
         String name = cmd.getHostName();
 
-        SearchBuilder<ManagementServerHostVO> sb = managementServerHostDao.createSearchBuilder();
-        SearchCriteria<ManagementServerHostVO> sc = sb.create();
+        SearchBuilder<ManagementServerJoinVO> sb = managementServerJoinDao.createSearchBuilder();
+        SearchCriteria<ManagementServerJoinVO> sc = sb.create();
         if (id != null) {
             sc.addAnd("id", SearchCriteria.Op.EQ, id);
         }
         if (name != null) {
             sc.addAnd("name", SearchCriteria.Op.EQ, name);
         }
-        return managementServerHostDao.searchAndCount(sc, null);
+        return managementServerJoinDao.searchAndCount(sc, null);
     }
 
-    protected ManagementServerResponse createManagementServerResponse(ManagementServerHostVO mgmt) {
+    protected ManagementServerResponse createManagementServerResponse(ManagementServerJoinVO mgmt) {
         ManagementServerResponse mgmtResponse = new ManagementServerResponse();
         mgmtResponse.setId(mgmt.getUuid());
         mgmtResponse.setName(mgmt.getName());
         mgmtResponse.setState(mgmt.getState());
         mgmtResponse.setVersion(mgmt.getVersion());
+        mgmtResponse.setJavaVersion(mgmt.getJavaVersion());
+        mgmtResponse.setJavaDistribution(mgmt.getJavaName());
+        mgmtResponse.setOsDistribution(mgmt.getOsDistribution());
+        mgmtResponse.setLastServerStart(mgmt.getLastJvmStart());
+        mgmtResponse.setLastServerStop(mgmt.getLastJvmStop());
+        mgmtResponse.setLastBoot(mgmt.getLastSystemBoot());
         mgmtResponse.setObjectName("managementserver");
         return mgmtResponse;
     }
diff --git a/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDao.java
new file mode 100644
index 0000000000..bf45f80151
--- /dev/null
+++ b/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDao.java
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.dao;
+
+import com.cloud.api.query.vo.ManagementServerJoinVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface ManagementServerJoinDao  extends GenericDao<ManagementServerJoinVO, Long> {
+}
diff --git a/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDaoImpl.java
new file mode 100644
index 0000000000..cc5620144c
--- /dev/null
+++ b/server/src/main/java/com/cloud/api/query/dao/ManagementServerJoinDaoImpl.java
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.dao;
+
+import com.cloud.api.query.vo.ManagementServerJoinVO;
+import com.cloud.utils.db.GenericDaoBase;
+
+public class ManagementServerJoinDaoImpl  extends GenericDaoBase<ManagementServerJoinVO, Long> implements ManagementServerJoinDao {
+}
diff --git a/server/src/main/java/com/cloud/api/query/vo/ManagementServerJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/ManagementServerJoinVO.java
new file mode 100644
index 0000000000..be1a4c6f7f
--- /dev/null
+++ b/server/src/main/java/com/cloud/api/query/vo/ManagementServerJoinVO.java
@@ -0,0 +1,173 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.vo;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.management.ManagementServerHost;
+import org.apache.cloudstack.management.ManagementServerHost.State;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+
+/**
+ * The Value object for api response utility view for management server queries
+ */
+@Entity
+@Table(name = "mshost_view")
+public class ManagementServerJoinVO {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+
+    @Column(name = "uuid")
+    private String uuid;
+
+    @Column(name = "msid", updatable = true, nullable = false)
+    private long msid;
+
+    @Column(name = "runid", updatable = true, nullable = false)
+    private long runid;
+
+    @Column(name = "name", updatable = true, nullable = true)
+    private String name;
+
+    @Column(name = "state", updatable = true, nullable = false)
+    @Enumerated(value = EnumType.STRING)
+    private ManagementServerHost.State state;
+
+    @Column(name = "version", updatable = true, nullable = true)
+    private String version;
+
+    @Column(name = "service_ip", updatable = true, nullable = false)
+    private String serviceIP;
+
+    @Column(name = "service_port", updatable = true, nullable = false)
+    private int servicePort;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "last_update", updatable = true, nullable = true)
+    private Date lastUpdateTime;
+
+    @Column(name = GenericDao.REMOVED_COLUMN)
+    private Date removed;
+
+    @Column(name = "alert_count", updatable = true, nullable = false)
+    private int alertCount;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_jvm_start")
+    private Date lastJvmStart;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_jvm_stop")
+    private Date lastJvmStop;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name="last_system_boot")
+    private Date lastSystemBoot;
+
+    @Column(name="os_distribution")
+    private String osDistribution;
+
+    @Column(name="java_name")
+    private String javaName;
+
+    @Column(name="java_version")
+    private String javaVersion;
+
+    public long getId() {
+        return id;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public long getMsid() {
+        return msid;
+    }
+
+    public long getRunid() {
+        return runid;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public State getState() {
+        return state;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getServiceIP() {
+        return serviceIP;
+    }
+
+    public int getServicePort() {
+        return servicePort;
+    }
+
+    public Date getLastUpdateTime() {
+        return lastUpdateTime;
+    }
+
+    public Date getRemoved() {
+        return removed;
+    }
+
+    public int getAlertCount() {
+        return alertCount;
+    }
+
+    public Date getLastJvmStart() {
+        return lastJvmStart;
+    }
+
+    public Date getLastJvmStop() {
+        return lastJvmStop;
+    }
+
+    public Date getLastSystemBoot() {
+        return lastSystemBoot;
+    }
+
+    public String getOsDistribution() {
+        return osDistribution;
+    }
+
+    public String getJavaName() {
+        return javaName;
+    }
+
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+}
diff --git a/server/src/main/java/com/cloud/server/DbStatsCollection.java b/server/src/main/java/com/cloud/server/DbStatsCollection.java
new file mode 100644
index 0000000000..cb07582705
--- /dev/null
+++ b/server/src/main/java/com/cloud/server/DbStatsCollection.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.server;
+
+public interface DbStatsCollection {
+    String queries = "Queries";
+    String uptime = "Uptime";
+    String loadAvarages = "loadAverages";
+    String status = "STATUS";
+    String variables = "VARIABLES";
+    String connections = "Connections";
+    String currentTlsVersion = "Current_tls_version";
+    String version = "version";
+    String versionComment = "version_comment";
+    String collectionTime = "collectiontime";
+
+}
diff --git a/server/src/main/java/com/cloud/server/ManagementServerHostStatsEntry.java b/server/src/main/java/com/cloud/server/ManagementServerHostStatsEntry.java
new file mode 100644
index 0000000000..fb0084f3d7
--- /dev/null
+++ b/server/src/main/java/com/cloud/server/ManagementServerHostStatsEntry.java
@@ -0,0 +1,456 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.server;
+
+import java.util.Date;
+
+public class ManagementServerHostStatsEntry implements ManagementServerHostStats {
+
+    private long managementServerHostId;
+    private String managementServerHostUuid;
+
+    private Date collectionTime;
+    private long sessions;
+    private double cpuUtilization;
+    private long totalJvmMemoryBytes;
+    private long freeJvmMemoryBytes;
+    private long maxJvmMemoryBytes;
+    private long processJvmMemoryBytes;
+    private long jvmUptime;
+    private long jvmStartTime;
+    private int availableProcessors;
+    private double loadAverage;
+    long totalInit;
+    long totalUsed;
+    long totalCommitted;
+    private long pid;
+    private String jvmName;
+    private String jvmVendor;
+    private String jvmVersion;
+    private String osDistribution;
+    private int agentCount;
+
+    private long heapMemoryUsed;
+    private long heapMemoryTotal;
+    private int threadsBlockedCount;
+    private int threadsDaemonCount;
+    private int threadsRunnableCount;
+    private int threadsTerminatedCount;
+    private int threadsTotalCount;
+    private int threadsWaitingCount;
+    private long systemMemoryTotal;
+    private long systemMemoryFree;
+    private long systemMemoryUsed;
+    private long systemMemoryVirtualSize;
+    private String logInfo;
+    private double systemTotalCpuCycles;
+    private double[] systemLoadAverages;
+    private long[] systemCyclesUsage;
+    private boolean dbLocal;
+    private boolean usageLocal;
+
+    private Date systemBootTime;
+    private String kernelVersion;
+
+    public ManagementServerHostStatsEntry() {
+        this(new Date());
+    }
+
+    public ManagementServerHostStatsEntry(Date date) {
+        collectionTime = date;
+    }
+
+    @Override
+    public long getManagementServerHostId() {
+        return managementServerHostId;
+    }
+
+    public void setManagementServerHostId(long managementServerHostId) {
+        this.managementServerHostId = managementServerHostId;
+    }
+
+    @Override
+    public String getManagementServerHostUuid() {
+        return managementServerHostUuid;
+    }
+
+    public void setManagementServerHostUuid(String managementServerHostUuid) {
+        this.managementServerHostUuid = managementServerHostUuid;
+    }
+
+    @Override
+    public Date getCollectionTime(){
+        return collectionTime;
+    }
+
+    @Override
+    public long getSessions() {
+        return sessions;
+    }
+
+    @Override
+    public double getCpuUtilization() {
+        return cpuUtilization;
+    }
+
+    @Override
+    public long getTotalJvmMemoryBytes() {
+        return totalJvmMemoryBytes;
+    }
+
+    @Override
+    public double getFreeJvmMemoryBytes() {
+        return freeJvmMemoryBytes;
+    }
+
+    @Override
+    public long getProcessJvmMemoryBytes() {
+        return processJvmMemoryBytes;
+    }
+
+    @Override
+    public long getJvmUptime() {
+        return jvmUptime;
+    }
+
+    @Override
+    public long getJvmStartTime() {
+        return jvmStartTime;
+    }
+
+    @Override
+    public int getAvailableProcessors() {
+        return availableProcessors;
+    }
+
+    @Override
+    public double getLoadAverage() {
+        return loadAverage;
+    }
+
+    @Override
+    public long getTotalInit() {
+        return totalInit;
+    }
+
+    @Override
+    public long getTotalUsed() {
+        return totalUsed;
+    }
+
+    @Override
+    public long getMaxJvmMemoryBytes() {
+        return maxJvmMemoryBytes;
+    }
+
+    @Override
+    public long getTotalCommitted() {
+        return totalCommitted;
+    }
+
+    @Override
+    public long getPid() {
+        return pid;
+    }
+
+    @Override
+    public String getJvmName() {
+        return jvmName;
+    }
+
+    @Override
+    public String getJvmVendor() {
+        return jvmVendor;
+    }
+
+    @Override
+    public String getJvmVersion() {
+        return jvmVersion;
+    }
+
+    @Override
+    public String getOsDistribution() {
+        return osDistribution;
+    }
+
+    @Override
+    public int getAgentCount() {
+        return agentCount;
+    }
+
+    @Override
+    public long getHeapMemoryUsed() {
+        return heapMemoryUsed;
+    }
+
+    @Override
+    public long getHeapMemoryTotal() {
+        return heapMemoryTotal;
+    }
+
+    public void setSessions(long sessions) {
+        this.sessions = sessions;
+    }
+
+    public void setCpuUtilization(double cpuUtilization) {
+        this.cpuUtilization = cpuUtilization;
+    }
+
+    public void setTotalJvmMemoryBytes(long totalJvmMemoryBytes) {
+        this.totalJvmMemoryBytes = totalJvmMemoryBytes;
+    }
+
+    public void setFreeJvmMemoryBytes(long freeJvmMemoryBytes) {
+        this.freeJvmMemoryBytes = freeJvmMemoryBytes;
+    }
+
+    public void setProcessJvmMemoryBytes(long processJvmMemoryBytes) {
+        this.processJvmMemoryBytes = processJvmMemoryBytes;
+    }
+
+    protected void validateSome() {
+        assert totalJvmMemoryBytes - processJvmMemoryBytes > freeJvmMemoryBytes;
+    }
+
+    public void setJvmUptime(long jvmUptime) {
+        this.jvmUptime = jvmUptime;
+    }
+
+    public void setJvmStartTime(long jvmStartTime) {
+        this.jvmStartTime = jvmStartTime;
+    }
+
+    public void setAvailableProcessors(int availableProcessors) {
+        this.availableProcessors = availableProcessors;
+    }
+
+    public void setLoadAverage(double loadAverage) {
+        this.loadAverage = loadAverage;
+    }
+
+    public void setTotalInit(long totalInit) {
+        this.totalInit = totalInit;
+    }
+
+    public void setTotalUsed(long totalUsed) {
+        this.totalUsed = totalUsed;
+    }
+
+    public void setMaxJvmMemoryBytes(long maxJvmMemoryBytes) {
+        this.maxJvmMemoryBytes = maxJvmMemoryBytes;
+    }
+
+    public void setTotalCommitted(long totalCommitted) {
+        this.totalCommitted = totalCommitted;
+    }
+
+    public void setProcessId(long pid) {
+        this.pid = pid;
+    }
+
+    public void setJvmName(String name) {
+        this.jvmName = name;
+    }
+
+    public void setJvmVendor(String vmVendor) {
+        this.jvmVendor = vmVendor;
+    }
+
+    public void setJvmVersion(String vmVersion) {
+        this.jvmVersion = vmVersion;
+    }
+
+    public void setOsDistribution(String osDistribution) {
+        this.osDistribution = osDistribution;
+    }
+
+    public void setAgentCount(int agentCount) {
+        this.agentCount = agentCount;
+    }
+
+    public void setHeapMemoryUsed(long heapMemoryUsed) {
+        this.heapMemoryUsed = heapMemoryUsed;
+    }
+
+    public void setHeapMemoryTotal(long heapMemoryTotal) {
+        this.heapMemoryTotal = heapMemoryTotal;
+    }
+
+    public void setThreadsBlockedCount(int threadsBlockedCount) {
+        this.threadsBlockedCount = threadsBlockedCount;
+    }
+
+    @Override
+    public int getThreadsBlockedCount() {
+        return threadsBlockedCount;
+    }
+
+    public void setThreadsTotalCount(int threadsTotalCount) {
+        this.threadsTotalCount = threadsTotalCount;
+    }
+
+    @Override
+    public int getThreadsTotalCount() {
+        return threadsTotalCount;
+    }
+
+    public void setThreadsDaemonCount(int threadsDaemonCount) {
+        this.threadsDaemonCount = threadsDaemonCount;
+    }
+
+    @Override
+    public int getThreadsDaemonCount() {
+        return threadsDaemonCount;
+    }
+
+    public void setThreadsRunnableCount(int threadsRunnableCount) {
+        this.threadsRunnableCount = threadsRunnableCount;
+    }
+
+    @Override
+    public int getThreadsRunnableCount() {
+        return threadsRunnableCount;
+    }
+
+    public void setThreadsTerminatedCount(int threadsTerminatedCount) {
+        this.threadsTerminatedCount = threadsTerminatedCount;
+    }
+
+    @Override
+    public int getThreadsTerminatedCount() {
+        return threadsTerminatedCount;
+    }
+
+    public void setThreadsWaitingCount(int threadsWaitingCount) {
+        this.threadsWaitingCount = threadsWaitingCount;
+    }
+
+    @Override
+    public int getThreadsWaitingCount() {
+        return threadsWaitingCount;
+    }
+
+    public void setSystemMemoryTotal(long systemMemoryTotal) {
+        this.systemMemoryTotal = systemMemoryTotal;
+    }
+
+    @Override
+    public long getSystemMemoryTotal() {
+        return systemMemoryTotal;
+    }
+
+    public void setSystemMemoryFree(long systemMemoryFree) {
+        this.systemMemoryFree = systemMemoryFree;
+    }
+
+    @Override
+    public long getSystemMemoryFree() {
+        return systemMemoryFree;
+    }
+
+    public void setSystemMemoryUsed(long systemMemoryUsed) {
+        this.systemMemoryUsed = systemMemoryUsed;
+    }
+
+    @Override
+    public long getSystemMemoryUsed() {
+        return systemMemoryUsed;
+    }
+
+    public void setSystemMemoryVirtualSize(long systemMemoryVirtualSize) {
+        this.systemMemoryVirtualSize = systemMemoryVirtualSize;
+    }
+
+    @Override
+    public long getSystemMemoryVirtualSize() {
+        return systemMemoryVirtualSize;
+    }
+
+    public void setLogInfo(String logInfo) {
+        this.logInfo = logInfo;
+    }
+
+    @Override
+    public String getLogInfo() {
+        return logInfo;
+    }
+
+    public void setSystemTotalCpuCycles(double systemTotalCpuCycles) {
+        this.systemTotalCpuCycles = systemTotalCpuCycles;
+    }
+
+    @Override
+    public double getSystemTotalCpuCycles() {
+        return systemTotalCpuCycles;
+    }
+
+    public void setSystemLoadAverages(double[] systemLoadAverages) {
+        this.systemLoadAverages = systemLoadAverages;
+    }
+
+    @Override
+    public double[] getSystemLoadAverages() {
+        return systemLoadAverages;
+    }
+
+    public void setSystemCyclesUsage(long[] systemCyclesUsage) {
+        this.systemCyclesUsage = systemCyclesUsage;
+    }
+
+    @Override
+    public long[] getSystemCyclesUsage() {
+        return systemCyclesUsage;
+    }
+
+    public void setDbLocal(boolean dbLocal) {
+        this.dbLocal = dbLocal;
+    }
+
+    @Override
+    public boolean isDbLocal() {
+        return dbLocal;
+    }
+
+    public void setUsageLocal(boolean usageLocal) {
+        this.usageLocal = usageLocal;
+    }
+
+    @Override
+    public boolean isUsageLocal() {
+        return usageLocal;
+    }
+
+    @Override
+    public Date getSystemBootTime() {
+        return systemBootTime;
+    }
+
+    public void setSystemBootTime(Date systemBootTime) {
+        this.systemBootTime = systemBootTime;
+    }
+
+    public void setKernelVersion(String kernelVersion) {
+        this.kernelVersion = kernelVersion;
+    }
+
+    @Override
+    public String getKernelVersion() {
+        return kernelVersion;
+    }
+}
diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java
index ecea1318f1..252894c3cc 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -16,15 +16,24 @@
 // under the License.
 package com.cloud.server;
 
+import javax.inject.Inject;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+import java.lang.management.RuntimeMXBean;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
@@ -32,8 +41,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
-import javax.inject.Inject;
-
+import com.cloud.utils.db.DbUtil;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
@@ -43,14 +51,17 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.cloudstack.management.ManagementServerHost;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
 import org.apache.cloudstack.utils.graphite.GraphiteClient;
 import org.apache.cloudstack.utils.graphite.GraphiteException;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 import org.apache.cloudstack.utils.usage.UsageUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.time.DateUtils;
 import org.apache.commons.lang3.BooleanUtils;
@@ -61,6 +72,7 @@ import org.influxdb.InfluxDBFactory;
 import org.influxdb.dto.BatchPoints;
 import org.influxdb.dto.Point;
 import org.influxdb.dto.Pong;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.stereotype.Component;
 
 import com.cloud.agent.AgentManager;
@@ -74,9 +86,15 @@ import com.cloud.agent.api.VmNetworkStatsEntry;
 import com.cloud.agent.api.VmStatsEntry;
 import com.cloud.agent.api.VmStatsEntryBase;
 import com.cloud.agent.api.VolumeStatsEntry;
+import com.cloud.api.ApiSessionListener;
 import com.cloud.capacity.CapacityManager;
+import com.cloud.cluster.ClusterManager;
+import com.cloud.cluster.ClusterManagerListener;
+import com.cloud.cluster.ClusterServicePdu;
 import com.cloud.cluster.ManagementServerHostVO;
+import com.cloud.cluster.ManagementServerStatusVO;
 import com.cloud.cluster.dao.ManagementServerHostDao;
+import com.cloud.cluster.dao.ManagementServerStatusDao;
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.ClusterDao;
@@ -111,6 +129,7 @@ import com.cloud.network.as.dao.CounterDao;
 import com.cloud.org.Cluster;
 import com.cloud.resource.ResourceManager;
 import com.cloud.resource.ResourceState;
+import com.cloud.serializer.GsonHelper;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.ImageStoreDetailsUtil;
@@ -126,11 +145,13 @@ import com.cloud.user.UserStatisticsVO;
 import com.cloud.user.VmDiskStatisticsVO;
 import com.cloud.user.dao.UserStatisticsDao;
 import com.cloud.user.dao.VmDiskStatisticsDao;
+import com.cloud.utils.LogUtils;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.ComponentMethodInterceptable;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.DbProperties;
 import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.SearchCriteria;
@@ -139,6 +160,7 @@ import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.MacAddress;
+import com.cloud.utils.script.Script;
 import com.cloud.vm.NicVO;
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.UserVmVO;
@@ -150,17 +172,46 @@ import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.cloud.vm.dao.VmStatsDao;
+
+import com.codahale.metrics.JvmAttributeGaugeSet;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricSet;
+import com.codahale.metrics.jvm.BufferPoolMetricSet;
+import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
+import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
+import com.codahale.metrics.jvm.ThreadStatesGaugeSet;
 import com.google.gson.Gson;
+import com.google.gson.JsonParseException;
+import com.google.gson.reflect.TypeToken;
+import com.sun.management.OperatingSystemMXBean;
 
 import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
-import org.apache.commons.io.FileUtils;
 
 /**
  * Provides real time stats for various agent resources up to x seconds
  *
+ * @startuml
+ *
+ * StatsCollector -> ClusterManager : register
+ * ClusterManager -> StatsCollector : onManagementNodeJoined
+ * StatsCollector -> list : add MS
+ * ClusterManager -> StatsCollector : onManagementNodeJoined
+ * StatsCollector -> list : add MS to send list
+ * StatsCollector -> collector : update own status
+ * StatsCollector -> list : get all ms ids
+ * StatsCollector -> ClusterManager : update status for my (ms id) to all ms_ids
+ * ClusterManager -> ClusterManager : update ms_ids on status on (ms id)
+ * ClusterManager -> StatsCollector : onManagementNodeLeft
+ * StatsCollector -> list : add MS
+ * ClusterManager -> StatsCollector : status data updated for (ms id)
+ * StatsCollector -> StatsCollector : update entry for (ms id)
+ * ClusterManager -> StatsCollector : onManagementNodeLeft
+ * StatsCollector -> list : add MS
+ * @enduml
  */
 @Component
-public class StatsCollector extends ManagerBase implements ComponentMethodInterceptable, Configurable {
+public class StatsCollector extends ManagerBase implements ComponentMethodInterceptable, Configurable, DbStatsCollection {
 
     public static enum ExternalStatsProtocol {
         NONE("none"), GRAPHITE("graphite"), INFLUXDB("influxdb");
@@ -176,7 +227,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         }
     }
 
-    public static final Logger s_logger = Logger.getLogger(StatsCollector.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(StatsCollector.class);
 
     private static final int UNDEFINED_PORT_VALUE = -1;
 
@@ -213,24 +264,37 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     private static final String INFLUXDB_HOST_MEASUREMENT = "host_stats";
     private static final String INFLUXDB_VM_MEASUREMENT = "vm_stats";
 
-    private static final ConfigKey<Integer> vmDiskStatsInterval = new ConfigKey<Integer>("Advanced", Integer.class, "vm.disk.stats.interval", "0",
+    public static final ConfigKey<Integer> MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL = new ConfigKey<>("Advanced",
+            Integer.class, "management.server.stats.interval", "60",
+            "Time interval in seconds, for management servers stats collection. Set to <= 0 to disable management servers stats.", false);
+    private static final ConfigKey<Integer> DATABASE_SERVER_STATUS_COLLECTION_INTERVAL = new ConfigKey<>("Advanced",
+            Integer.class, "database.server.stats.interval", "60",
+            "Time interval in seconds, for database servers stats collection. Set to <= 0 to disable database servers stats.", false);
+    private static final ConfigKey<Integer> DATABASE_SERVER_LOAD_HISTORY_RETENTION_NUMBER = new ConfigKey<>("Advanced",
+            Integer.class, "database.server.stats.retention", "3",
+            "The number of queries/seconds values to retain in history. This will define for how many periods of 'database.server.stats.interval' seconds, the queries/seconds values will be kept in memory",
+            true);
+    private static final ConfigKey<Integer> vmDiskStatsInterval = new ConfigKey<>("Advanced", Integer.class, "vm.disk.stats.interval", "0",
             "Interval (in seconds) to report vm disk statistics. Vm disk statistics will be disabled if this is set to 0 or less than 0.", false);
-    private static final ConfigKey<Integer> vmDiskStatsIntervalMin = new ConfigKey<Integer>("Advanced", Integer.class, "vm.disk.stats.interval.min", "300",
+    private static final ConfigKey<Integer> vmDiskStatsIntervalMin = new ConfigKey<>("Advanced", Integer.class, "vm.disk.stats.interval.min", "300",
             "Minimal interval (in seconds) to report vm disk statistics. If vm.disk.stats.interval is smaller than this, use this to report vm disk statistics.", false);
-    private static final ConfigKey<Integer> vmNetworkStatsInterval = new ConfigKey<Integer>("Advanced", Integer.class, "vm.network.stats.interval", "0",
+    private static final ConfigKey<Integer> vmNetworkStatsInterval = new ConfigKey<>("Advanced", Integer.class, "vm.network.stats.interval", "0",
             "Interval (in seconds) to report vm network statistics (for Shared networks). Vm network statistics will be disabled if this is set to 0 or less than 0.", false);
-    private static final ConfigKey<Integer> vmNetworkStatsIntervalMin = new ConfigKey<Integer>("Advanced", Integer.class, "vm.network.stats.interval.min", "300",
+    private static final ConfigKey<Integer> vmNetworkStatsIntervalMin = new ConfigKey<>("Advanced", Integer.class, "vm.network.stats.interval.min", "300",
             "Minimal Interval (in seconds) to report vm network statistics (for Shared networks). If vm.network.stats.interval is smaller than this, use this to report vm network statistics.",
             false);
-    private static final ConfigKey<Integer> StatsTimeout = new ConfigKey<Integer>("Advanced", Integer.class, "stats.timeout", "60000",
+    private static final ConfigKey<Integer> StatsTimeout = new ConfigKey<>("Advanced", Integer.class, "stats.timeout", "60000",
             "The timeout for stats call in milli seconds.", true,
             ConfigKey.Scope.Cluster);
-    private static final ConfigKey<String> statsOutputUri = new ConfigKey<String>("Advanced", String.class, "stats.output.uri", "",
+    private static final ConfigKey<String> statsOutputUri = new ConfigKey<>("Advanced", String.class, "stats.output.uri", "",
             "URI to send StatsCollector statistics to. The collector is defined on the URI scheme. Example: graphite://graphite-hostaddress:port or influxdb://influxdb-hostaddress/dbname. Note that the port is optional, if not added the default port for the respective collector (graphite or influxdb) will be used. Additionally, the database name '/dbname' is  also optional; default db name is 'cloudstack'. You must create and configure the database if using influxdb.",
             true);
     protected static ConfigKey<Boolean> vmStatsIncrementMetrics = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.stats.increment.metrics", "true",
             "When set to 'true', VM metrics(NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs and DiskWriteIOs) that are collected from the hypervisor are summed before being returned."
             + "On the other hand, when set to 'false', the VM metrics API will just display the latest metrics collected.", true);
+    private static final ConfigKey<Boolean> VM_STATS_INCREMENT_METRICS_IN_MEMORY = new ConfigKey<>("Advanced", Boolean.class, "vm.stats.increment.metrics.in.memory", "true",
+            "When set to 'true', VM metrics(NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs and DiskWriteIOs) that are collected from the hypervisor are summed and stored in memory. "
+            + "On the other hand, when set to 'false', the VM metrics API will just display the latest metrics collected.", true);
     protected static ConfigKey<Integer> vmStatsMaxRetentionTime = new ConfigKey<Integer>("Advanced", Integer.class, "vm.stats.max.retention.time", "1",
             "The maximum time (in minutes) for keeping VM stats records in the database. The VM stats cleanup process will be disabled if this is set to 0 or less than 0.", true);
 
@@ -268,8 +332,6 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     @Inject
     private VmDiskStatisticsDao _vmDiskStatsDao;
     @Inject
-    private ManagementServerHostDao _msHostDao;
-    @Inject
     private UserStatisticsDao _userStatsDao;
     @Inject
     private NicDao _nicDao;
@@ -303,12 +365,19 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     private ImageStoreDetailsUtil imageStoreDetailsUtil;
     @Inject
     private ManagementServerHostDao managementServerHostDao;
+    // stats collector is now a clustered agent
+    @Inject
+    private ClusterManager clusterManager;
+    @Inject
+    private ManagementServerStatusDao managementServerStatusDao;
 
-    private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>();
-    protected ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>();
-    private final Map<String, VolumeStats> _volumeStats = new ConcurrentHashMap<String, VolumeStats>();
-    private ConcurrentHashMap<Long, StorageStats> _storageStats = new ConcurrentHashMap<Long, StorageStats>();
-    private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<Long, StorageStats>();
+    private final ConcurrentHashMap<String, ManagementServerHostStats> managementServerHostStats = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<String, Object> dbStats = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<>();
+    protected ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<>();
+    private final Map<String, VolumeStats> _volumeStats = new ConcurrentHashMap<>();
+    private ConcurrentHashMap<Long, StorageStats> _storageStats = new ConcurrentHashMap<>();
+    private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<>();
 
     private static final long DEFAULT_INITIAL_DELAY = 15000L;
 
@@ -333,6 +402,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     private boolean _dailyOrHourly = false;
     protected long managementServerNodeId = ManagementServerNode.getManagementServerId();
     protected long msId = managementServerNodeId;
+    final static MetricRegistry METRIC_REGISTRY = new MetricRegistry();
 
     public static StatsCollector getInstance() {
         return s_instance;
@@ -350,8 +420,30 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     @Override
     public boolean start() {
         init(_configDao.getConfiguration());
+        registerAll("gc", new GarbageCollectorMetricSet(), METRIC_REGISTRY);
+        registerAll("buffers", new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer()), METRIC_REGISTRY);
+        registerAll("memory", new MemoryUsageGaugeSet(), METRIC_REGISTRY);
+        registerAll("threads", new ThreadStatesGaugeSet(), METRIC_REGISTRY);
+        registerAll("jvm", new JvmAttributeGaugeSet(), METRIC_REGISTRY);
         return true;
     }
+    @Override
+    public boolean stop() {
+        _executor.shutdown();
+        return true;
+    }
+
+    private void registerAll(String prefix, MetricSet metricSet, MetricRegistry registry) {
+        String registryTemplate = new String(prefix + "%s");
+        for (Map.Entry<String, Metric> entry : metricSet.getMetrics().entrySet()) {
+            String registryName = String.format(registryTemplate, entry.getKey());
+            if (entry.getValue() instanceof MetricSet) {
+                registerAll(registryName, (MetricSet) entry.getValue(), registry);
+            } else {
+                registry.register(registryName, entry.getValue());
+            }
+        }
+    }
 
     protected void init(Map<String, String> configs) {
         _executor = Executors.newScheduledThreadPool(6, new NamedThreadFactory("StatsCollector"));
@@ -361,6 +453,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), ONE_MINUTE_IN_MILLISCONDS);
         volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), ONE_MINUTE_IN_MILLISCONDS);
         autoScaleStatsInterval = NumbersUtil.parseLong(configs.get("autoscale.stats.interval"), ONE_MINUTE_IN_MILLISCONDS);
+        ManagementServerStatusAdministrator managementServerStatusAdministrator = new ManagementServerStatusAdministrator();
+        clusterManager.registerStatusAdministrator(managementServerStatusAdministrator);
+        clusterManager.registerListener(managementServerStatusAdministrator);
+
+        gson = GsonHelper.getGson();
 
         String statsUri = statsOutputUri.value();
         if (StringUtils.isNotBlank(statsUri)) {
@@ -371,7 +468,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 try {
                     externalStatsType = ExternalStatsProtocol.valueOf(externalStatsScheme.toUpperCase());
                 } catch (IllegalArgumentException e) {
-                    s_logger.error(externalStatsScheme + " is not a valid protocol for external statistics. No statistics will be send.");
+                    LOGGER.error(externalStatsScheme + " is not a valid protocol for external statistics. No statistics will be send.");
                 }
 
                 if (StringUtils.isNotEmpty(uri.getHost())) {
@@ -394,7 +491,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 }
 
             } catch (URISyntaxException e) {
-                s_logger.error("Failed to parse external statistics URI: ", e);
+                LOGGER.error("Failed to parse external statistics URI: ", e);
             }
         }
 
@@ -405,11 +502,14 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         if (vmStatsInterval > 0) {
             _executor.scheduleWithFixedDelay(new VmStatsCollector(), DEFAULT_INITIAL_DELAY, vmStatsInterval, TimeUnit.MILLISECONDS);
         } else {
-            s_logger.info("Skipping collect VM stats. The global parameter vm.stats.interval is set to 0 or less than 0.");
+            LOGGER.info("Skipping collect VM stats. The global parameter vm.stats.interval is set to 0 or less than 0.");
         }
 
         _executor.scheduleWithFixedDelay(new VmStatsCleaner(), DEFAULT_INITIAL_DELAY, 60000L, TimeUnit.MILLISECONDS);
 
+        scheduleCollection(MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL, new ManagementServerCollector(), 1L);
+        scheduleCollection(DATABASE_SERVER_STATUS_COLLECTION_INTERVAL, new DbCollector(), 0L);
+
         if (storageStatsInterval > 0) {
             _executor.scheduleWithFixedDelay(new StorageCollector(), DEFAULT_INITIAL_DELAY, storageStatsInterval, TimeUnit.MILLISECONDS);
         }
@@ -420,26 +520,26 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
 
         if (vmDiskStatsInterval.value() > 0) {
             if (vmDiskStatsInterval.value() < vmDiskStatsIntervalMin.value()) {
-                s_logger.debug("vm.disk.stats.interval - " + vmDiskStatsInterval.value() + " is smaller than vm.disk.stats.interval.min - " + vmDiskStatsIntervalMin.value()
+                LOGGER.debug("vm.disk.stats.interval - " + vmDiskStatsInterval.value() + " is smaller than vm.disk.stats.interval.min - " + vmDiskStatsIntervalMin.value()
                         + ", so use vm.disk.stats.interval.min");
                 _executor.scheduleAtFixedRate(new VmDiskStatsTask(), vmDiskStatsIntervalMin.value(), vmDiskStatsIntervalMin.value(), TimeUnit.SECONDS);
             } else {
                 _executor.scheduleAtFixedRate(new VmDiskStatsTask(), vmDiskStatsInterval.value(), vmDiskStatsInterval.value(), TimeUnit.SECONDS);
             }
         } else {
-            s_logger.debug("vm.disk.stats.interval - " + vmDiskStatsInterval.value() + " is 0 or less than 0, so not scheduling the vm disk stats thread");
+            LOGGER.debug("vm.disk.stats.interval - " + vmDiskStatsInterval.value() + " is 0 or less than 0, so not scheduling the vm disk stats thread");
         }
 
         if (vmNetworkStatsInterval.value() > 0) {
             if (vmNetworkStatsInterval.value() < vmNetworkStatsIntervalMin.value()) {
-                s_logger.debug("vm.network.stats.interval - " + vmNetworkStatsInterval.value() + " is smaller than vm.network.stats.interval.min - "
+                LOGGER.debug("vm.network.stats.interval - " + vmNetworkStatsInterval.value() + " is smaller than vm.network.stats.interval.min - "
                         + vmNetworkStatsIntervalMin.value() + ", so use vm.network.stats.interval.min");
                 _executor.scheduleAtFixedRate(new VmNetworkStatsTask(), vmNetworkStatsIntervalMin.value(), vmNetworkStatsIntervalMin.value(), TimeUnit.SECONDS);
             } else {
                 _executor.scheduleAtFixedRate(new VmNetworkStatsTask(), vmNetworkStatsInterval.value(), vmNetworkStatsInterval.value(), TimeUnit.SECONDS);
             }
         } else {
-            s_logger.debug("vm.network.stats.interval - " + vmNetworkStatsInterval.value() + " is 0 or less than 0, so not scheduling the vm network stats thread");
+            LOGGER.debug("vm.network.stats.interval - " + vmNetworkStatsInterval.value() + " is 0 or less than 0, so not scheduling the vm network stats thread");
         }
 
         if (volumeStatsInterval > 0) {
@@ -481,7 +581,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
             _dailyOrHourly = false;
         }
         if (_usageAggregationRange < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) {
-            s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
+            LOGGER.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
             _usageAggregationRange = UsageUtils.USAGE_AGGREGATION_RANGE_MIN;
         }
 
@@ -492,11 +592,23 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         if (mgmtServerVo != null) {
             msId = mgmtServerVo.getId();
         } else {
-            s_logger.warn(String.format("Cannot find management server with msid [%s]. "
+            LOGGER.warn(String.format("Cannot find management server with msid [%s]. "
                     + "Therefore, VM stats will be recorded with the management server MAC address converted as a long in the mgmt_server_id column.", managementServerNodeId));
         }
     }
 
+    private void scheduleCollection(ConfigKey<Integer> statusCollectionInterval, AbstractStatsCollector collector, long delay) {
+        if (statusCollectionInterval.value() > 0) {
+            _executor.scheduleAtFixedRate(collector,
+                    delay,
+                    statusCollectionInterval.value(),
+                    TimeUnit.SECONDS);
+        } else {
+                LOGGER.debug(String.format("%s - %d is 0 or less, so not scheduling the status collector thread",
+                        statusCollectionInterval.key(), statusCollectionInterval.value()));
+        }
+    }
+
     /**
      * Configures the database name according to the URI path. For instance, if the URI is as influxdb://address:port/dbname, the database name will be 'dbname'.
      */
@@ -536,7 +648,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         @Override
         protected void runInContext() {
             try {
-                s_logger.debug("HostStatsCollector is running...");
+                LOGGER.debug("HostStatsCollector is running...");
 
                 SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance();
 
@@ -544,13 +656,13 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 List<HostVO> hosts = _hostDao.search(sc, null);
 
                 for (HostVO host : hosts) {
-                    HostStatsEntry hostStatsEntry = (HostStatsEntry)_resourceMgr.getHostStatistics(host.getId());
+                    HostStatsEntry hostStatsEntry = (HostStatsEntry) _resourceMgr.getHostStatistics(host.getId());
                     if (hostStatsEntry != null) {
                         hostStatsEntry.setHostVo(host);
                         metrics.put(hostStatsEntry.getHostId(), hostStatsEntry);
                         _hostStats.put(host.getId(), hostStatsEntry);
                     } else {
-                        s_logger.warn("The Host stats is null for host: " + host.getId());
+                        LOGGER.warn("The Host stats is null for host: " + host.getId());
                     }
                 }
 
@@ -560,7 +672,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
 
                 updateGpuEnabledHostsDetails(hosts);
             } catch (Throwable t) {
-                s_logger.error("Error trying to retrieve host stats", t);
+                LOGGER.error("Error trying to retrieve host stats", t);
             }
         }
 
@@ -587,16 +699,496 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         }
 
         @Override
-        protected Point creteInfluxDbPoint(Object metricsObject) {
+        protected Point createInfluxDbPoint(Object metricsObject) {
             return createInfluxDbPointForHostMetrics(metricsObject);
         }
     }
 
+     class DbCollector extends AbstractStatsCollector {
+         List<Double> loadHistory = new ArrayList<>();
+         DbCollector() {
+             dbStats.put(loadAvarages, loadHistory);
+         }
+         @Override
+         protected void runInContext() {
+             LOGGER.debug(String.format("%s is running...", this.getClass().getSimpleName()));
+
+             try {
+                 int lastUptime = (dbStats.containsKey(uptime) ? (Integer) dbStats.get(uptime) : 0);
+                 int lastQueries = (dbStats.containsKey(queries) ? (Integer) dbStats.get(queries) : 0);
+                 getDynamicDataFromDB();
+                 int interval = (Integer) dbStats.get(uptime) - lastUptime;
+                 int activity = (Integer) dbStats.get(queries) - lastQueries;
+                 loadHistory.add(0, Double.valueOf(activity / interval));
+                 int maxsize = DATABASE_SERVER_LOAD_HISTORY_RETENTION_NUMBER.value();
+                 while (loadHistory.size() > maxsize) {
+                     loadHistory.remove(maxsize - 1);
+                 }
+             } catch (Throwable e) {
+                 // pokemon catch to make sure the thread stays running
+                 LOGGER.error("db statistics collection failed due to " + e.getLocalizedMessage());
+                 if (LOGGER.isDebugEnabled()) {
+                     LOGGER.debug("db statistics collection failed.", e);
+                 }
+             }
+         }
+
+         private void getDynamicDataFromDB() {
+             Map<String, String> stats = DbUtil.getDbInfo("STATUS", queries, uptime);
+             dbStats.put(collectionTime, new Date());
+             dbStats.put(queries, (Integer.valueOf(stats.get(queries))));
+             dbStats.put(uptime, (Integer.valueOf(stats.get(uptime))));
+         }
+
+
+         @Override
+         protected Point createInfluxDbPoint(Object metricsObject) {
+             return null;
+         }
+     }
+
+    class ManagementServerCollector extends AbstractStatsCollector {
+        @Override
+        protected void runInContext() {
+            LOGGER.debug(String.format("%s is running...", this.getClass().getSimpleName()));
+            long msid = ManagementServerNode.getManagementServerId();
+            ManagementServerHostVO mshost = null;
+            ManagementServerHostStatsEntry hostStatsEntry = null;
+            try {
+                mshost = managementServerHostDao.findByMsid(msid);
+                // get local data
+                hostStatsEntry = getDataFrom(mshost);
+                managementServerHostStats.put(mshost.getUuid(), hostStatsEntry);
+                // send to other hosts
+                clusterManager.publishStatus(gson.toJson(hostStatsEntry));
+            } catch (Throwable t) {
+                // pokemon catch to make sure the thread stays running
+                LOGGER.error("Error trying to retrieve management server host statistics", t);
+            }
+            try {
+                // send to DB
+                storeStatus(hostStatsEntry, mshost);
+            } catch (Throwable t) {
+                // pokemon catch to make sure the thread stays running
+                LOGGER.error("Error trying to store  management server host statistics", t);
+            }
+        }
+
+        private void storeStatus(ManagementServerHostStatsEntry hostStatsEntry, ManagementServerHostVO mshost) {
+            if (hostStatsEntry == null || mshost == null) {
+                return;
+            }
+            ManagementServerStatusVO msStats = managementServerStatusDao.findByMsId(hostStatsEntry.getManagementServerHostUuid());
+            if (msStats == null) {
+                LOGGER.info(String.format("creating new status info record for host %s - %s",
+                        mshost.getName(),
+                        hostStatsEntry.getManagementServerHostUuid()));
+                msStats = new ManagementServerStatusVO();
+                msStats.setMsId(hostStatsEntry.getManagementServerHostUuid());
+            }
+            msStats.setOsDistribution(hostStatsEntry.getOsDistribution()); // for now just the bunch details come later
+            msStats.setJavaName(hostStatsEntry.getJvmVendor());
+            msStats.setJavaVersion(hostStatsEntry.getJvmVersion());
+            Date startTime = new Date(hostStatsEntry.getJvmStartTime());
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format("reporting starttime %s", startTime));
+            }
+            msStats.setLastJvmStart(startTime);
+            msStats.setLastSystemBoot(hostStatsEntry.getSystemBootTime());
+            msStats.setUpdated(new Date());
+            managementServerStatusDao.persist(msStats);
+        }
+
+        @NotNull
+        private ManagementServerHostStatsEntry getDataFrom(ManagementServerHostVO mshost) {
+            ManagementServerHostStatsEntry newEntry = new ManagementServerHostStatsEntry();
+            LOGGER.trace("Metrics collection start...");
+            newEntry.setManagementServerHostId(mshost.getId());
+            newEntry.setManagementServerHostUuid(mshost.getUuid());
+            newEntry.setDbLocal(isDbLocal());
+            newEntry.setUsageLocal(isUsageLocal());
+            retrieveSession(newEntry);
+            getJvmDimensions(newEntry);
+            LOGGER.trace("Metrics collection extra...");
+            getRuntimeData(newEntry);
+            getMemoryData(newEntry);
+            // newEntry must now include a pid!
+            getProcFileSystemData(newEntry);
+            // proc memory data has precedence over mbean memory data
+            getCpuData(newEntry);
+            getFileSystemData(newEntry);
+            getDataBaseStatistics(newEntry, mshost.getMsid());
+            gatherAllMetrics(newEntry);
+            LOGGER.trace("Metrics collection end!");
+            return newEntry;
+        }
+
+        private void retrieveSession(ManagementServerHostStatsEntry newEntry) {
+            long sessions = ApiSessionListener.getSessionCount();
+            newEntry.setSessions(sessions);
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format("Sessions found in Api %d vs context %d", sessions,ApiSessionListener.getNumberOfSessions()));
+            } else {
+                LOGGER.debug("Sessions active: " + sessions);
+            }
+        }
+
+        private void getDataBaseStatistics(ManagementServerHostStatsEntry newEntry, long msid) {
+            int count = _hostDao.countByMs(msid);
+            newEntry.setAgentCount(count);
+        }
+
+        private void getMemoryData(@NotNull ManagementServerHostStatsEntry newEntry) {
+            MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean();
+            newEntry.setTotalInit(mxBean.getHeapMemoryUsage().getInit() + mxBean.getNonHeapMemoryUsage().getInit());
+            newEntry.setTotalUsed(mxBean.getHeapMemoryUsage().getUsed() + mxBean.getNonHeapMemoryUsage().getUsed());
+            newEntry.setMaxJvmMemoryBytes(mxBean.getHeapMemoryUsage().getMax() + mxBean.getNonHeapMemoryUsage().getMax());
+            newEntry.setTotalCommitted(mxBean.getHeapMemoryUsage().getCommitted() + mxBean.getNonHeapMemoryUsage().getCommitted());
+        }
+
+        private void getCpuData(@NotNull ManagementServerHostStatsEntry newEntry) {
+            java.lang.management.OperatingSystemMXBean bean = ManagementFactory.getOperatingSystemMXBean();
+            newEntry.setAvailableProcessors(bean.getAvailableProcessors());
+            newEntry.setLoadAverage(bean.getSystemLoadAverage());
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format(
+                        "Metrics processors - %d , loadavg - %f ",
+                        newEntry.getAvailableProcessors(),
+                        newEntry.getLoadAverage()));
+            }
+            if (bean instanceof OperatingSystemMXBean) {
+                OperatingSystemMXBean mxBean = (OperatingSystemMXBean) bean;
+                // if we got these from /proc, skip the bean
+                if (newEntry.getSystemMemoryTotal() == 0) {
+                    newEntry.setSystemMemoryTotal(mxBean.getTotalPhysicalMemorySize());
+                }
+                if (newEntry.getSystemMemoryFree() == 0) {
+                    newEntry.setSystemMemoryFree(mxBean.getFreePhysicalMemorySize());
+                }
+                if (newEntry.getSystemMemoryUsed() <= 0) {
+                    newEntry.setSystemMemoryUsed(mxBean.getCommittedVirtualMemorySize());
+                }
+                if (LOGGER.isTraceEnabled()) {
+                    LOGGER.trace(String.format("data from 'OperatingSystemMXBean': total mem: %d, free mem: %d, used mem: %d",
+                            newEntry.getSystemMemoryTotal(),
+                            newEntry.getSystemMemoryFree(),
+                            newEntry.getSystemMemoryUsed()));
+                }
+            }
+        }
+
+        private void getRuntimeData(@NotNull ManagementServerHostStatsEntry newEntry) {
+            final RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean();
+            newEntry.setJvmUptime(mxBean.getUptime());
+            newEntry.setJvmStartTime(mxBean.getStartTime());
+            newEntry.setProcessId(mxBean.getPid());
+            newEntry.setJvmName(mxBean.getName());
+            newEntry.setJvmVendor(mxBean.getVmVendor());
+            newEntry.setJvmVersion(mxBean.getVmVersion());
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format(
+                        "Metrics uptime - %d , starttime - %d",
+                        newEntry.getJvmUptime(),
+                        newEntry.getJvmStartTime()));
+            }
+        }
+
+        private void getJvmDimensions(@NotNull ManagementServerHostStatsEntry newEntry) {
+            Runtime runtime = Runtime.getRuntime();
+            newEntry.setTotalJvmMemoryBytes(runtime.totalMemory());
+            newEntry.setFreeJvmMemoryBytes(runtime.freeMemory());
+            newEntry.setMaxJvmMemoryBytes(runtime.maxMemory());
+            //long maxMem = runtime.maxMemory();
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format(
+                        "Metrics proc - %d , maxMem - %d , totalMemory - %d , freeMemory - %f ",
+                        newEntry.getAvailableProcessors(),
+                        newEntry.getMaxJvmMemoryBytes(),
+                        newEntry.getTotalJvmMemoryBytes(),
+                        newEntry.getFreeJvmMemoryBytes()));
+            }
+        }
+
+        /**
+         * As for data from outside the JVM, we only rely on /proc/ contained data.
+         *
+         * @param newEntry item to add the information to
+         */
+        private void getProcFileSystemData(@NotNull ManagementServerHostStatsEntry newEntry) {
+            // this should be taken from ("cat /proc/version"), not sure how standard this /etc entry is
+            String OS = Script.runSimpleBashScript("cat /etc/os-release | grep PRETTY_NAME | cut -f2 -d '=' | tr -d '\"'");
+            newEntry.setOsDistribution(OS);
+            String kernel = Script.runSimpleBashScript("uname -r");
+            newEntry.setKernelVersion(kernel);
+            // if we got these from the bean, skip
+            if (newEntry.getSystemMemoryTotal() == 0) {
+                String mem = Script.runSimpleBashScript("cat /proc/meminfo | grep MemTotal | cut -f 2 -d ':' | tr -d 'a-zA-z '").trim();
+                newEntry.setSystemMemoryTotal(Long.parseLong(mem) * ByteScaleUtils.KiB);
+                LOGGER.info(String.format("system memory from /proc: %d", newEntry.getSystemMemoryTotal()));
+            }
+            if (newEntry.getSystemMemoryFree() == 0) {
+                String free = Script.runSimpleBashScript("cat /proc/meminfo | grep MemFree | cut -f 2 -d ':' | tr -d 'a-zA-z '").trim();
+                newEntry.setSystemMemoryFree(Long.parseLong(free) * ByteScaleUtils.KiB);
+                LOGGER.info(String.format("free memory from /proc: %d", newEntry.getSystemMemoryFree()));
+            }
+            if (newEntry.getSystemMemoryUsed() <= 0) {
+                String used = Script.runSimpleBashScript(String.format("ps -o rss= %d", newEntry.getPid()));
+                newEntry.setSystemMemoryUsed(Long.parseLong(used));
+                LOGGER.info(String.format("used memory from /proc: %d", newEntry.getSystemMemoryUsed()));
+            }
+            try {
+                String bootTime = Script.runSimpleBashScript("uptime -s");
+                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.ENGLISH);
+                Date date = formatter.parse(bootTime);
+                newEntry.setSystemBootTime(date);
+            } catch (ParseException e) {
+                LOGGER.error("can not retrieve system uptime");
+            }
+            String maxuse = Script.runSimpleBashScript(String.format("ps -o vsz= %d", newEntry.getPid()));
+            newEntry.setSystemMemoryVirtualSize(Long.parseLong(maxuse) * 1024);
+
+            newEntry.setSystemTotalCpuCycles(getSystemCpuCyclesTotal());
+            newEntry.setSystemLoadAverages(getCpuLoads());
+
+            newEntry.setSystemCyclesUsage(getSystemCpuUsage());
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace(
+                        String.format("cpu\ncapacities: %f\n     loads: %s ; %s ; %s\n     stats: %d ; %d ; %d",
+                                newEntry.getSystemTotalCpuCycles(),
+                                newEntry.getSystemLoadAverages()[0], newEntry.getSystemLoadAverages()[1], newEntry.getSystemLoadAverages()[2],
+                                newEntry.getSystemCyclesUsage()[0], newEntry.getSystemCyclesUsage()[1], newEntry.getSystemCyclesUsage()[2]
+                        )
+                );
+            }
+        }
+
+        @NotNull
+        private double[] getCpuLoads() {
+            String[] cpuloadString = Script.runSimpleBashScript("cat /proc/loadavg").split(" ");
+            double[] cpuloads = {Double.parseDouble(cpuloadString[0]), Double.parseDouble(cpuloadString[1]), Double.parseDouble(cpuloadString[2])};
+            return cpuloads;
+        }
+
+        private long [] getSystemCpuUsage() {
+            String[] cpustats = Script.runSimpleBashScript("cat /proc/stat | grep \"cpu \" | tr -d \"cpu\"").trim().split(" ");
+            long [] cycleUsage = {Long.parseLong(cpustats[0]) + Long.parseLong(cpustats[1]), Long.parseLong(cpustats[2]), Long.parseLong(cpustats[3])};
+            return cycleUsage;
+        }
+
+        private double getSystemCpuCyclesTotal() {
+            String cpucaps = Script.runSimpleBashScript("cat /proc/cpuinfo | grep \"cpu MHz\" | grep \"cpu MHz\" | cut -f 2 -d : | tr -d ' '| tr '\\n' \" \"");
+            double totalcpucap = 0;
+            for (String cpucap : cpucaps.split(" ")) {
+                totalcpucap += Double.parseDouble(cpucap);
+            }
+            return totalcpucap;
+        }
+
+        private void getFileSystemData(@NotNull ManagementServerHostStatsEntry newEntry) {
+            Set<String> logFileNames = LogUtils.getLogFileNames();
+            StringBuilder logInfoBuilder = new StringBuilder();
+            for (String fileName : logFileNames) {
+                String du = Script.runSimpleBashScript(String.format("du -sh %s | cut -f '1'", fileName));
+                String df = Script.runSimpleBashScript(String.format("df -h %s | grep -v Filesystem | awk '{print \"on disk \" $1 \" mounted on \" $6 \" (\" $5 \" full)\"}'", fileName));
+                logInfoBuilder.append(fileName).append(" using: ").append(du).append('\n').append(df);
+            }
+            newEntry.setLogInfo(logInfoBuilder.toString());
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace("log stats:\n" + newEntry.getLogInfo());
+            }
+        }
+
+        private void gatherAllMetrics(ManagementServerHostStatsEntry metricsEntry) {
+            Map<String, Object> metricDetails = new HashMap<>();
+            for (String metricName : METRIC_REGISTRY.getGauges().keySet()) {
+                Object value = getMetric(metricName);
+                metricDetails.put(metricName, value);
+                if (LOGGER.isTraceEnabled()) {
+                    LOGGER.trace(String.format("Metrics collection '%s'=%s", metricName, value));
+                }
+                // gather what we need from this list
+                extractDetailToField(metricsEntry, metricName, value);
+            }
+        }
+
+        /**
+         * store a value in the local fields of newEntry
+         *
+         * @param metricsEntry the stats info we need to communicate
+         * @param metricName the detail to extract
+         * @param value ;)
+         */
+        private void extractDetailToField(ManagementServerHostStatsEntry metricsEntry, String metricName, Object value) {
+            switch (metricName) {
+                case "memoryheap.used":
+                    metricsEntry.setHeapMemoryUsed((Long) value);
+                    break;
+                case "memoryheap.max":
+                    metricsEntry.setHeapMemoryTotal((Long) value);
+                    break;
+                case "threadsblocked.count":
+                    metricsEntry.setThreadsBlockedCount((Integer) value);
+                    break;
+                case "threadscount":
+                    metricsEntry.setThreadsTotalCount((Integer) value);
+                    break;
+                case "threadsdaemon.count":
+                    metricsEntry.setThreadsDaemonCount((Integer) value);
+                    break;
+                case "threadsrunnable.count":
+                    metricsEntry.setThreadsRunnableCount((Integer) value);
+                    break;
+                case "threadsterminated.count":
+                    metricsEntry.setThreadsTerminatedCount((Integer) value);
+                    break;
+                case "threadswaiting.count":
+                    metricsEntry.setThreadsWaitingCount((Integer) value);
+                    break;
+                case "threadsdeadlocks":
+                case "threadsnew.count":
+                case "threadstimed_waiting.count":
+                default:
+                    LOGGER.debug(String.format("not storing detail %s, %s", metricName, value));
+                    /*
+                     * 'buffers.direct.capacity'=8192 type=Long
+                     * 'buffers.direct.count'=1 type=Long
+                     * 'buffers.direct.used'=8192 type=Long
+                     * 'buffers.mapped.capacity'=0 type=Long
+                     * 'buffers.mapped.count'=0 type=Long
+                     * 'buffers.mapped.used'=0 type=Long
+                     * 'gc.G1-Old-Generation.count'=0 type=Long
+                     * 'gc.G1-Old-Generation.time'=0 type=Long
+                     * 'gc.G1-Young-Generation.count'=36 type=Long
+                     * 'gc.G1-Young-Generation.time'=678 type=Long
+                     * 'jvm.name'=532601@matah type=String
+                     * 'jvm.uptime'=272482 type=Long
+                     * 'jvm.vendor'=Red Hat, Inc. OpenJDK 64-Bit Server VM 11.0.12+7 (11) type=String
+                     * 'memory.heap.committed'=1200619520 type=Long
+                     * 'memory.heap.init'=522190848 type=Long
+                     *+ 'memoryheap.max'=4294967296 type=Long
+                     * 'memory.heap.usage'=0.06405723094940186 type=Double
+                     *+ 'memoryheap.used'=275123712 type=Long
+                     * 'memory.non-heap.committed'=217051136 type=Long
+                     * 'memory.non-heap.init'=7667712 type=Long
+                     * 'memory.non-heap.max'=-1 type=Long
+                     * 'memory.non-heap.usage'=-2.11503936E8 type=Double
+                     * 'memory.non-heap.used'=211503936 type=Long
+                     * 'memory.pools.CodeHeap-'non-nmethods'.usage'=0.3137061403508772 type=Double
+                     * 'memory.pools.CodeHeap-'non-profiled-nmethods'.usage'=0.16057488836310319 type=Double
+                     * 'memory.pools.CodeHeap-'profiled-nmethods'.usage'=0.3391885643349885 type=Double
+                     * 'memory.pools.Compressed-Class-Space.usage'=0.012650594115257263 type=Double
+                     * 'memory.pools.G1-Eden-Space.usage'=0.005822416302765648 type=Double
+                     * 'memory.pools.G1-Old-Gen.usage'=0.054535746574401855 type=Double
+                     * 'memory.pools.G1-Survivor-Space.usage'=1.0 type=Double
+                     * 'memory.pools.Metaspace.usage'=0.9765298966718151 type=Double
+                     * 'memory.total.committed'=1417670656 type=Long
+                     * 'memory.total.init'=529858560 type=Long
+                     * 'memory.total.max'=4294967295 type=Long
+                     * 'memory.total.used'=486627648 type=Long
+                     *+ 'threadsblocked.count'=1 type=Integer
+                     *+ 'threadscount'=439 type=Integer
+                     *+ 'threadsdaemon.count'=12 type=Integer
+                     * 'threadsdeadlocks'=[] type=EmptySet
+                     * 'threads.new.count'=0 type=Integer
+                     *+ 'threadsrunnable.count'=5 type=Integer
+                     *+ 'threadsterminated.count'=0 type=Integer
+                     * 'threads.timed_waiting.count'=52 type=Integer
+                     *+ 'threadswaiting.count'=381 type=Integer
+                     */
+                    break;
+            }
+        }
+
+        private Object getMetric(String metricName) {
+            return METRIC_REGISTRY.getGauges().get(metricName).getValue();
+        }
+
+        @Override
+        protected Point createInfluxDbPoint(Object metricsObject) {
+            return null;
+        }
+
+    }
+
+    /**
+     * @return true if there is a usage server installed locally.
+     */
+    protected boolean isUsageLocal() {
+        boolean local = false;
+        String usageInstall = Script.runSimpleBashScript("systemctl status cloudstack-usage | grep \"  Loaded:\"");
+        LOGGER.debug(String.format("usage install: %s", usageInstall));
+
+        if (StringUtils.isNotBlank(usageInstall)) {
+            local = usageInstall.contains("enabled");
+        }
+        return local;
+    }
+
+    /**
+     * @return true if the DB endpoint is local to this server
+     */
+    protected boolean isDbLocal() {
+        Properties p = getDbProperties();
+        String configeredHost = p.getProperty("db.cloud.host");
+        String localHost = p.getProperty("cluster.node.IP");
+        // see if these resolve to the same
+        if ("localhost".equals(configeredHost)) return true;
+        if ("127.0.0.1".equals(configeredHost)) return true;
+        if ("::1".equals(configeredHost)) return true;
+        if (StringUtils.isNotBlank(configeredHost) && StringUtils.isNotBlank(localHost) && configeredHost.equals(localHost)) return true;
+        return false;
+    }
+
+    protected Properties getDbProperties() {
+        return DbProperties.getDbProperties();
+    }
+
+    protected class ManagementServerStatusAdministrator implements ClusterManager.StatusAdministrator, ClusterManagerListener {
+        @Override
+        public String newStatus(ClusterServicePdu pdu) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(String.format("StatusUpdate from %s, json: %s", pdu.getSourcePeer(), pdu.getJsonPackage()));
+            }
+
+            ManagementServerHostStatsEntry hostStatsEntry = null;
+            try {
+                hostStatsEntry = gson.fromJson(pdu.getJsonPackage(),new TypeToken<ManagementServerHostStatsEntry>(){}.getType());
+                managementServerHostStats.put(hostStatsEntry.getManagementServerHostUuid(), hostStatsEntry);
+            } catch (JsonParseException e) {
+                LOGGER.error("Exception in decoding of other MS hosts status from : " + pdu.getSourcePeer());
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("Exception in decoding of other MS hosts status: ", e);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void onManagementNodeJoined(List<? extends ManagementServerHost> nodeList, long selfNodeId) {
+            // do nothing, but wait for the status to come through
+        }
+
+        @Override
+        public void onManagementNodeLeft(List<? extends ManagementServerHost> nodeList, long selfNodeId) {
+            // remove the status for those ones
+            for (ManagementServerHost node : nodeList) {
+                LOGGER.info(String.format("node %s (%s) at %s (%od) is reported to have left the cluster, invalidating status.",node.getName(), node.getUuid(), node.getServiceIP(), node.getMsid()));
+                managementServerHostStats.remove(node.getUuid());
+            }
+        }
+
+        @Override
+        public void onManagementNodeIsolated() {
+            LOGGER.error(String.format("This management server is reported to be isolated (msid %d", mgmtSrvrId));
+            // not sure if anything should be done now.
+        }
+    }
+
     class VmStatsCollector extends AbstractStatsCollector {
         @Override
         protected void runInContext() {
             try {
-                s_logger.debug("VmStatsCollector is running...");
+                LOGGER.trace("VmStatsCollector is running...");
 
                 SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance();
                 List<HostVO> hosts = _hostDao.search(sc, null);
@@ -644,18 +1236,18 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                             metrics.clear();
                         }
                     } catch (Exception e) {
-                        s_logger.debug("Failed to get VM stats for host with ID: " + host.getId());
+                        LOGGER.debug("Failed to get VM stats for host with ID: " + host.getId());
                         continue;
                     }
                 }
 
             } catch (Throwable t) {
-                s_logger.error("Error trying to retrieve VM stats", t);
+                LOGGER.error("Error trying to retrieve VM stats", t);
             }
         }
 
         @Override
-        protected Point creteInfluxDbPoint(Object metricsObject) {
+        protected Point createInfluxDbPoint(Object metricsObject) {
             return createInfluxDbPointForVmMetrics(metricsObject);
         }
     }
@@ -754,9 +1346,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) {
                     //Check for ownership
                     //msHost in UP state with min id should run the job
-                    ManagementServerHostVO msHost = _msHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
+                    ManagementServerHostVO msHost = managementServerHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
                     if (msHost == null || (msHost.getMsid() != mgmtSrvrId)) {
-                        s_logger.debug("Skipping aggregate disk stats update");
+                        LOGGER.debug("Skipping aggregate disk stats update");
                         scanLock.unlock();
                         return;
                     }
@@ -776,17 +1368,17 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                         _vmDiskStatsDao.update(stat.getId(), stat);
                                     }
                                 }
-                                s_logger.debug("Successfully updated aggregate vm disk stats");
+                                LOGGER.debug("Successfully updated aggregate vm disk stats");
                             }
                         });
                     } catch (Exception e) {
-                        s_logger.debug("Failed to update aggregate disk stats", e);
+                        LOGGER.debug("Failed to update aggregate disk stats", e);
                     } finally {
                         scanLock.unlock();
                     }
                 }
             } catch (Exception e) {
-                s_logger.debug("Exception while trying to acquire disk stats lock", e);
+                LOGGER.debug("Exception while trying to acquire disk stats lock", e);
             } finally {
                 scanLock.releaseRef();
             }
@@ -798,13 +1390,13 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         protected void runInContext() {
             //Check for ownership
             //msHost in UP state with min id should run the job
-            ManagementServerHostVO msHost = _msHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
+            ManagementServerHostVO msHost = managementServerHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
             if (msHost == null || (msHost.getMsid() != mgmtSrvrId)) {
-                s_logger.debug("Skipping collect vm disk stats from hosts");
+                LOGGER.debug("Skipping collect vm disk stats from hosts");
                 return;
             }
             // collect the vm disk statistics(total) from hypervisor. added by weizhou, 2013.03.
-            s_logger.debug("VmDiskStatsTask is running...");
+            LOGGER.debug("VmDiskStatsTask is running...");
 
             SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance();
             sc.addAnd("hypervisorType", SearchCriteria.Op.IN, HypervisorType.KVM, HypervisorType.VMware);
@@ -846,26 +1438,26 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     VmDiskStatisticsVO vmDiskStat_lock = _vmDiskStatsDao.lock(userVm.getAccountId(), userVm.getDataCenterId(), vmId, volume.getId());
 
                                     if (areAllDiskStatsZero(vmDiskStat)) {
-                                        s_logger.debug("IO/bytes read and write are all 0. Not updating vm_disk_statistics");
+                                        LOGGER.debug("IO/bytes read and write are all 0. Not updating vm_disk_statistics");
                                         continue;
                                     }
 
                                     if (vmDiskStat_lock == null) {
-                                        s_logger.warn("unable to find vm disk stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()
+                                        LOGGER.warn("unable to find vm disk stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()
                                                 + " and volumeId:" + volume.getId());
                                         continue;
                                     }
 
                                     if (isCurrentVmDiskStatsDifferentFromPrevious(previousVmDiskStats, vmDiskStat_lock)) {
-                                        s_logger.debug("vm disk stats changed from the time GetVmDiskStatsCommand was sent. " + "Ignoring current answer. Host: " + host.getName()
+                                        LOGGER.debug("vm disk stats changed from the time GetVmDiskStatsCommand was sent. " + "Ignoring current answer. Host: " + host.getName()
                                                 + " . VM: " + vmDiskStat.getVmName() + " Read(Bytes): " + toHumanReadableSize(vmDiskStat.getBytesRead()) + " write(Bytes): " + toHumanReadableSize(vmDiskStat.getBytesWrite())
                                                 + " Read(IO): " + toHumanReadableSize(vmDiskStat.getIORead()) + " write(IO): " + toHumanReadableSize(vmDiskStat.getIOWrite()));
                                         continue;
                                     }
 
                                     if (vmDiskStat_lock.getCurrentBytesRead() > vmDiskStat.getBytesRead()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Read # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Read # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmDiskStat.getVmName() + " Reported: " + toHumanReadableSize(vmDiskStat.getBytesRead()) + " Stored: "
                                                     + vmDiskStat_lock.getCurrentBytesRead());
                                         }
@@ -873,8 +1465,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     }
                                     vmDiskStat_lock.setCurrentBytesRead(vmDiskStat.getBytesRead());
                                     if (vmDiskStat_lock.getCurrentBytesWrite() > vmDiskStat.getBytesWrite()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Write # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Write # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmDiskStat.getVmName() + " Reported: " + toHumanReadableSize(vmDiskStat.getBytesWrite()) + " Stored: "
                                                     + toHumanReadableSize(vmDiskStat_lock.getCurrentBytesWrite()));
                                         }
@@ -882,8 +1474,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     }
                                     vmDiskStat_lock.setCurrentBytesWrite(vmDiskStat.getBytesWrite());
                                     if (vmDiskStat_lock.getCurrentIORead() > vmDiskStat.getIORead()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Read # of IO that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Read # of IO that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmDiskStat.getVmName() + " Reported: " + vmDiskStat.getIORead() + " Stored: "
                                                     + vmDiskStat_lock.getCurrentIORead());
                                         }
@@ -891,8 +1483,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     }
                                     vmDiskStat_lock.setCurrentIORead(vmDiskStat.getIORead());
                                     if (vmDiskStat_lock.getCurrentIOWrite() > vmDiskStat.getIOWrite()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Write # of IO that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Write # of IO that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmDiskStat.getVmName() + " Reported: " + vmDiskStat.getIOWrite() + " Stored: "
                                                     + vmDiskStat_lock.getCurrentIOWrite());
                                         }
@@ -914,7 +1506,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                         }
                     });
                 } catch (Exception e) {
-                    s_logger.warn(String.format("Error while collecting vm disk stats from host %s : ", host.getName()), e);
+                    LOGGER.warn(String.format("Error while collecting vm disk stats from host %s : ", host.getName()), e);
                 }
             }
         }
@@ -925,13 +1517,13 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         protected void runInContext() {
             //Check for ownership
             //msHost in UP state with min id should run the job
-            ManagementServerHostVO msHost = _msHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
+            ManagementServerHostVO msHost = managementServerHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
             if (msHost == null || (msHost.getMsid() != mgmtSrvrId)) {
-                s_logger.debug("Skipping collect vm network stats from hosts");
+                LOGGER.debug("Skipping collect vm network stats from hosts");
                 return;
             }
             // collect the vm network statistics(total) from hypervisor
-            s_logger.debug("VmNetworkStatsTask is running...");
+            LOGGER.debug("VmNetworkStatsTask is running...");
 
             SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance();
             List<HostVO> hosts = _hostDao.search(sc, null);
@@ -960,10 +1552,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     continue;
                                 UserVmVO userVm = _userVmDao.findById(vmId);
                                 if (userVm == null) {
-                                    s_logger.debug("Cannot find uservm with id: " + vmId + " , continue");
+                                    LOGGER.debug("Cannot find uservm with id: " + vmId + " , continue");
                                     continue;
                                 }
-                                s_logger.debug("Now we are updating the user_statistics table for VM: " + userVm.getInstanceName()
+                                LOGGER.debug("Now we are updating the user_statistics table for VM: " + userVm.getInstanceName()
                                         + " after collecting vm network statistics from host: " + host.getName());
                                 for (VmNetworkStatsEntry vmNetworkStat : vmNetworkStats) {
                                     SearchCriteria<NicVO> sc_nic = _nicDao.createSearchCriteria();
@@ -983,27 +1575,27 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                             nic.getIPv4Address(), vmId, "UserVm");
 
                                     if ((vmNetworkStat.getBytesSent() == 0) && (vmNetworkStat.getBytesReceived() == 0)) {
-                                        s_logger.debug("bytes sent and received are all 0. Not updating user_statistics");
+                                        LOGGER.debug("bytes sent and received are all 0. Not updating user_statistics");
                                         continue;
                                     }
 
                                     if (vmNetworkStat_lock == null) {
-                                        s_logger.warn("unable to find vm network stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()
+                                        LOGGER.warn("unable to find vm network stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()
                                                 + " and nicId:" + nic.getId());
                                         continue;
                                     }
 
                                     if (previousvmNetworkStats != null && ((previousvmNetworkStats.getCurrentBytesSent() != vmNetworkStat_lock.getCurrentBytesSent())
                                             || (previousvmNetworkStats.getCurrentBytesReceived() != vmNetworkStat_lock.getCurrentBytesReceived()))) {
-                                        s_logger.debug("vm network stats changed from the time GetNmNetworkStatsCommand was sent. " + "Ignoring current answer. Host: "
+                                        LOGGER.debug("vm network stats changed from the time GetNmNetworkStatsCommand was sent. " + "Ignoring current answer. Host: "
                                                 + host.getName() + " . VM: " + vmNetworkStat.getVmName() + " Sent(Bytes): " + vmNetworkStat.getBytesSent() + " Received(Bytes): "
                                                 + vmNetworkStat.getBytesReceived());
                                         continue;
                                     }
 
                                     if (vmNetworkStat_lock.getCurrentBytesSent() > vmNetworkStat.getBytesSent()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Sent # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Sent # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmNetworkStat.getVmName() + " Reported: " + toHumanReadableSize(vmNetworkStat.getBytesSent()) + " Stored: "
                                                     + toHumanReadableSize(vmNetworkStat_lock.getCurrentBytesSent()));
                                         }
@@ -1012,8 +1604,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     vmNetworkStat_lock.setCurrentBytesSent(vmNetworkStat.getBytesSent());
 
                                     if (vmNetworkStat_lock.getCurrentBytesReceived() > vmNetworkStat.getBytesReceived()) {
-                                        if (s_logger.isDebugEnabled()) {
-                                            s_logger.debug("Received # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
+                                        if (LOGGER.isDebugEnabled()) {
+                                            LOGGER.debug("Received # of bytes that's less than the last one.  " + "Assuming something went wrong and persisting it. Host: "
                                                     + host.getName() + " . VM: " + vmNetworkStat.getVmName() + " Reported: " + toHumanReadableSize(vmNetworkStat.getBytesReceived()) + " Stored: "
                                                     + toHumanReadableSize(vmNetworkStat_lock.getCurrentBytesReceived()));
                                         }
@@ -1033,7 +1625,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                         }
                     });
                 } catch (Exception e) {
-                    s_logger.warn(String.format("Error while collecting vm network stats from host %s : ", host.getName()), e);
+                    LOGGER.warn(String.format("Error while collecting vm network stats from host %s : ", host.getName()), e);
                 }
             }
         }
@@ -1049,7 +1641,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                     List<VolumeVO> volumes = _volsDao.findByPoolId(pool.getId(), null);
                     for (VolumeVO volume : volumes) {
                         if (volume.getFormat() != ImageFormat.QCOW2 && volume.getFormat() != ImageFormat.VHD && volume.getFormat() != ImageFormat.OVA && (volume.getFormat() != ImageFormat.RAW || pool.getPoolType() != Storage.StoragePoolType.PowerFlex)) {
-                            s_logger.warn("Volume stats not implemented for this format type " + volume.getFormat());
+                            LOGGER.warn("Volume stats not implemented for this format type " + volume.getFormat());
                             break;
                         }
                     }
@@ -1075,12 +1667,12 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                             }
                         }
                     } catch (Exception e) {
-                        s_logger.warn("Failed to get volume stats for cluster with ID: " + pool.getClusterId(), e);
+                        LOGGER.warn("Failed to get volume stats for cluster with ID: " + pool.getClusterId(), e);
                         continue;
                     }
                 }
             } catch (Throwable t) {
-                s_logger.error("Error trying to retrieve volume stats", t);
+                LOGGER.error("Error trying to retrieve volume stats", t);
             }
         }
     }
@@ -1096,8 +1688,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         @Override
         protected void runInContext() {
             try {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("StorageCollector is running...");
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("StorageCollector is running...");
                 }
 
                 List<DataStore> stores = _dataStoreMgr.listImageStores();
@@ -1111,14 +1703,14 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                     GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), nfsVersion);
                     EndPoint ssAhost = _epSelector.select(store);
                     if (ssAhost == null) {
-                        s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName());
+                        LOGGER.debug("There is no secondary storage VM for secondary storage host " + store.getName());
                         continue;
                     }
                     long storeId = store.getId();
                     Answer answer = ssAhost.sendMessage(command);
                     if (answer != null && answer.getResult()) {
                         storageStats.put(storeId, (StorageStats)answer);
-                        s_logger.trace("HostId: " + storeId + " Used: " + toHumanReadableSize(((StorageStats)answer).getByteUsed()) + " Total Available: " + toHumanReadableSize(((StorageStats)answer).getCapacityBytes()));
+                        LOGGER.trace("HostId: " + storeId + " Used: " + toHumanReadableSize(((StorageStats)answer).getByteUsed()) + " Total Available: " + toHumanReadableSize(((StorageStats)answer).getCapacityBytes()));
                     }
                 }
                 _storageStats = storageStats;
@@ -1144,7 +1736,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                                     pool.setCapacityBytes(((StorageStats)answer).getCapacityBytes());
                                     poolNeedsUpdating = true;
                                 } else {
-                                    s_logger.warn("Not setting capacity bytes, received " + ((StorageStats)answer).getCapacityBytes()  + " capacity for pool ID " + poolId);
+                                    LOGGER.warn("Not setting capacity bytes, received " + ((StorageStats)answer).getCapacityBytes()  + " capacity for pool ID " + poolId);
                                 }
                             }
                             if (pool.getUsedBytes() != ((StorageStats)answer).getByteUsed() && (pool.getStorageProviderName().equalsIgnoreCase(DataStoreProvider.DEFAULT_PRIMARY) || _storageManager.canPoolProvideStorageStats(pool))) {
@@ -1157,14 +1749,14 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                             }
                         }
                     } catch (StorageUnavailableException e) {
-                        s_logger.info("Unable to reach " + pool, e);
+                        LOGGER.info("Unable to reach " + pool, e);
                     } catch (Exception e) {
-                        s_logger.warn("Unable to get stats for " + pool, e);
+                        LOGGER.warn("Unable to get stats for " + pool, e);
                     }
                 }
                 _storagePoolStats = storagePoolStats;
             } catch (Throwable t) {
-                s_logger.error("Error trying to retrieve storage stats", t);
+                LOGGER.error("Error trying to retrieve storage stats", t);
             }
         }
     }
@@ -1173,8 +1765,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         @Override
         protected void runInContext() {
             try {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("AutoScaling Monitor is running...");
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("AutoScaling Monitor is running...");
                 }
                 // list all AS VMGroups
                 List<AutoScaleVmGroupVO> asGroups = _asGroupDao.listAll();
@@ -1199,9 +1791,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                         asGroup.setLastInterval(new Date());
                         _asGroupDao.persist(asGroup);
 
-                        // collect RRDs data for this group
-                        if (s_logger.isDebugEnabled()) {
-                            s_logger.debug("[AutoScale] Collecting RRDs data...");
+                        if (LOGGER.isDebugEnabled()) {
+                            LOGGER.debug("[AutoScale] Collecting RRDs data...");
                         }
                         Map<String, String> params = new HashMap<String, String>();
                         List<AutoScaleVmGroupVmMapVO> asGroupVmVOs = _asGroupVmDao.listByGroup(asGroup.getId());
@@ -1242,10 +1833,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                         try {
                             Answer answer = _agentMgr.send(receiveHost, perfMon);
                             if (answer == null || !answer.getResult()) {
-                                s_logger.debug("Failed to send data to node !");
+                                LOGGER.debug("Failed to send data to node !");
                             } else {
                                 String result = answer.getDetails();
-                                s_logger.debug("[AutoScale] RRDs collection answer: " + result);
+                                LOGGER.debug("[AutoScale] RRDs collection answer: " + result);
                                 HashMap<Long, Double> avgCounter = new HashMap<Long, Double>();
 
                                 // extract data
@@ -1291,7 +1882,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
 
                                     String scaleAction = getAutoscaleAction(avgCounter, asGroup.getId(), currentVM, params);
                                     if (scaleAction != null) {
-                                        s_logger.debug("[AutoScale] Doing scale action: " + scaleAction + " for group " + asGroup.getId());
+                                        LOGGER.debug("[AutoScale] Doing scale action: " + scaleAction + " for group " + asGroup.getId());
                                         if (scaleAction.equals("scaleup")) {
                                             _asManager.doScaleUp(asGroup.getId(), 1);
                                         } else {
@@ -1309,7 +1900,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 }
 
             } catch (Throwable t) {
-                s_logger.error("Error trying to monitor autoscaling", t);
+                LOGGER.error("Error trying to monitor autoscaling", t);
             }
 
         }
@@ -1452,7 +2043,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
      * This class allows to writing metrics in InfluxDB for the table that matches the Collector extending it.
      * Thus, VmStatsCollector and HostCollector can use same method to write on different measures (host_stats or vm_stats table).
      */
-    abstract class AbstractStatsCollector extends ManagedContextRunnable {
+    abstract class  AbstractStatsCollector extends ManagedContextRunnable {
         /**
          * Sends metrics to influxdb host. This method supports both VM and Host metrics
          */
@@ -1468,10 +2059,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 Collection<Object> metricsObjects = metrics.values();
                 List<Point> points = new ArrayList<>();
 
-                s_logger.debug(String.format("Sending stats to %s host %s:%s", externalStatsType, externalStatsHost, externalStatsPort));
+                LOGGER.debug(String.format("Sending stats to %s host %s:%s", externalStatsType, externalStatsHost, externalStatsPort));
 
                 for (Object metricsObject : metricsObjects) {
-                    Point vmPoint = creteInfluxDbPoint(metricsObject);
+                    Point vmPoint = createInfluxDbPoint(metricsObject);
                     points.add(vmPoint);
                 }
                 writeBatches(influxDbConnection, databaseName, points);
@@ -1483,7 +2074,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         /**
          * Creates a InfluxDB point for the given stats collector (VmStatsCollector, or HostCollector).
          */
-        protected abstract Point creteInfluxDbPoint(Object metricsObject);
+        protected abstract Point createInfluxDbPoint(Object metricsObject);
     }
 
     public boolean imageStoreHasEnoughCapacity(DataStore imageStore) {
@@ -1495,7 +2086,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         StorageStats imageStoreStats = _storageStats.get(imageStoreId);
 
         if (imageStoreStats == null) {
-            s_logger.debug(String.format("Stats for image store [%s] not found.", imageStoreId));
+            LOGGER.debug(String.format("Stats for image store [%s] not found.", imageStoreId));
             return false;
         }
 
@@ -1505,13 +2096,13 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         String readableTotalCapacity = FileUtils.byteCountToDisplaySize((long) totalCapacity);
         String readableUsedCapacity = FileUtils.byteCountToDisplaySize((long) usedCapacity);
 
-        s_logger.debug(String.format("Verifying image storage [%s]. Capacity: total=[%s], used=[%s], threshold=[%s%%].", imageStoreId, readableTotalCapacity, readableUsedCapacity, threshold * 100));
+        LOGGER.debug(String.format("Verifying image storage [%s]. Capacity: total=[%s], used=[%s], threshold=[%s%%].", imageStoreId, readableTotalCapacity, readableUsedCapacity, threshold * 100));
 
         if (usedCapacity / totalCapacity <= threshold) {
             return true;
         }
 
-        s_logger.warn(String.format("Image storage [%s] has not enough capacity. Capacity: total=[%s], used=[%s], threshold=[%s%%].", imageStoreId, readableTotalCapacity, readableUsedCapacity, threshold * 100));
+        LOGGER.warn(String.format("Image storage [%s] has not enough capacity. Capacity: total=[%s], used=[%s], threshold=[%s%%].", imageStoreId, readableTotalCapacity, readableUsedCapacity, threshold * 100));
         return false;
     }
 
@@ -1538,12 +2129,12 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
      * Sends VMs metrics to the configured graphite host.
      */
     protected void sendVmMetricsToGraphiteHost(Map<Object, Object> metrics, HostVO host) {
-        s_logger.debug(String.format("Sending VmStats of host %s to %s host %s:%s", host.getId(), externalStatsType, externalStatsHost, externalStatsPort));
+        LOGGER.debug(String.format("Sending VmStats of host %s to %s host %s:%s", host.getId(), externalStatsType, externalStatsHost, externalStatsPort));
         try {
             GraphiteClient g = new GraphiteClient(externalStatsHost, externalStatsPort);
             g.sendMetrics(metrics);
         } catch (GraphiteException e) {
-            s_logger.debug("Failed sending VmStats to Graphite host " + externalStatsHost + ":" + externalStatsPort + ": " + e.getMessage());
+            LOGGER.debug("Failed sending VmStats to Graphite host " + externalStatsHost + ":" + externalStatsPort + ": " + e.getMessage());
         }
     }
 
@@ -1581,7 +2172,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 statsForCurrentIteration.getDiskWriteKBs(), statsForCurrentIteration.getDiskReadIOs(), statsForCurrentIteration.getDiskWriteIOs(),
                 statsForCurrentIteration.getEntityType());
         VmStatsVO vmStatsVO = new VmStatsVO(statsForCurrentIteration.getVmId(), msId, timestamp, gson.toJson(vmStats));
-        s_logger.trace(String.format("Recording VM stats: [%s].", vmStatsVO.toString()));
+        LOGGER.trace(String.format("Recording VM stats: [%s].", vmStatsVO.toString()));
         vmStatsDao.persist(vmStatsVO);
     }
 
@@ -1592,11 +2183,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     protected void cleanUpVirtualMachineStats() {
         Integer maxRetentionTime = vmStatsMaxRetentionTime.value();
         if (maxRetentionTime <= 0) {
-            s_logger.debug(String.format("Skipping VM stats cleanup. The [%s] parameter [%s] is set to 0 or less than 0.",
+            LOGGER.debug(String.format("Skipping VM stats cleanup. The [%s] parameter [%s] is set to 0 or less than 0.",
                     vmStatsMaxRetentionTime.scope(), vmStatsMaxRetentionTime.toString()));
             return;
         }
-        s_logger.trace("Removing older VM stats records.");
+        LOGGER.trace("Removing older VM stats records.");
         Date now = new Date();
         Date limit = DateUtils.addMinutes(now, -maxRetentionTime);
         vmStatsDao.removeAllByTimestampLessThan(limit);
@@ -1735,6 +2326,15 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         return _hostStats.get(hostId);
     }
 
+    public Map<String, Object> getDbStats() {
+        return dbStats;
+    }
+
+
+    public ManagementServerHostStats getManagementServerHostStats(String managementServerUuid) {
+        return managementServerHostStats.get(managementServerUuid);
+    }
+
     public StorageStats getStoragePoolStats(long id) {
         return _storagePoolStats.get(id);
     }
@@ -1747,7 +2347,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout, statsOutputUri,
-            vmStatsIncrementMetrics, vmStatsMaxRetentionTime};
+            vmStatsIncrementMetrics, vmStatsMaxRetentionTime,
+                VM_STATS_INCREMENT_METRICS_IN_MEMORY,
+                MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL,
+                DATABASE_SERVER_STATUS_COLLECTION_INTERVAL,
+                DATABASE_SERVER_LOAD_HISTORY_RETENTION_NUMBER};
     }
 
     public double getImageStoreCapacityThreshold() {
diff --git a/server/src/test/async-job-component.xml b/server/src/test/async-job-component.xml
index fbe1015cbe..413194c671 100644
--- a/server/src/test/async-job-component.xml
+++ b/server/src/test/async-job-component.xml
@@ -85,6 +85,7 @@
     <dao name="Console Proxy" class="com.cloud.vm.dao.ConsoleProxyDaoImpl" />
     <dao name="Upgrade" class="com.cloud.maint.dao.AgentUpgradeDaoImpl" />
     <dao name="Management Server Host" class="com.cloud.cluster.dao.ManagementServerHostDaoImpl" />
+    <dao name="Management Server Status" class="com.cloud.cluster.dao.ManagementServerStatusDaoImpl" />
     <dao name="Snapshot" class="com.cloud.storage.dao.SnapshotDaoImpl" />
     <dao name="ScheduledVMBackup" class="com.cloud.user.dao.ScheduledVMBackupDaoImpl" />
     <dao name="AsyncJobDao" class="com.cloud.async.dao.AsyncJobDaoImpl" />
diff --git a/server/src/test/java/com/cloud/server/StatsCollectorTest.java b/server/src/test/java/com/cloud/server/StatsCollectorTest.java
index f32b05e4dd..206b6b81f7 100644
--- a/server/src/test/java/com/cloud/server/StatsCollectorTest.java
+++ b/server/src/test/java/com/cloud/server/StatsCollectorTest.java
@@ -20,13 +20,14 @@ package com.cloud.server;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.concurrent.TimeUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.Properties;
 
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.influxdb.InfluxDB;
@@ -58,6 +59,8 @@ import com.cloud.vm.dao.VmStatsDao;
 import com.tngtech.java.junit.dataprovider.DataProvider;
 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
 
+import static org.mockito.Mockito.when;
+
 @RunWith(PowerMockRunner.class)
 @PowerMockRunnerDelegate(DataProviderRunner.class)
 @PrepareForTest({InfluxDBFactory.class, BatchPoints.class})
@@ -108,7 +111,7 @@ public class StatsCollectorTest {
         statsCollector.externalStatsHost = HOST_ADDRESS;
         statsCollector.externalStatsPort = INFLUXDB_DEFAULT_PORT;
         InfluxDB influxDbConnection = Mockito.mock(InfluxDB.class);
-        Mockito.when(influxDbConnection.databaseExists(DEFAULT_DATABASE_NAME)).thenReturn(databaseExists);
+        when(influxDbConnection.databaseExists(DEFAULT_DATABASE_NAME)).thenReturn(databaseExists);
         PowerMockito.mockStatic(InfluxDBFactory.class);
         PowerMockito.when(InfluxDBFactory.connect(URL)).thenReturn(influxDbConnection);
 
@@ -125,7 +128,7 @@ public class StatsCollectorTest {
         BatchPoints batchPoints = Mockito.mock(BatchPoints.class);
         PowerMockito.mockStatic(BatchPoints.class);
         PowerMockito.when(BatchPoints.database(DEFAULT_DATABASE_NAME)).thenReturn(builder);
-        Mockito.when(builder.build()).thenReturn(batchPoints);
+        when(builder.build()).thenReturn(batchPoints);
         Map<String, String> tagsToAdd = new HashMap<>();
         tagsToAdd.put("hostId", "1");
         Map<String, Object> fieldsToAdd = new HashMap<>();
@@ -133,7 +136,7 @@ public class StatsCollectorTest {
         Point point = Point.measurement("measure").tag(tagsToAdd).time(System.currentTimeMillis(), TimeUnit.MILLISECONDS).fields(fieldsToAdd).build();
         List<Point> points = new ArrayList<>();
         points.add(point);
-        Mockito.when(batchPoints.point(point)).thenReturn(batchPoints);
+        when(batchPoints.point(point)).thenReturn(batchPoints);
 
         statsCollector.writeBatches(influxDbConnection, DEFAULT_DATABASE_NAME, points);
 
@@ -376,4 +379,46 @@ public class StatsCollectorTest {
         Assert.assertEquals(6.2, result.getDiskWriteIOs(), 0);
     }
 
+    @Test
+    public void testIsDbIpv6Local() {
+        Properties p = new Properties();
+        p.put("db.cloud.host", "::1");
+        when(statsCollector.getDbProperties()).thenReturn(p);
+
+        Assert.assertTrue(statsCollector.isDbLocal());
+    }
+    @Test
+    public void testIsDbIpv4Local() {
+        Properties p = new Properties();
+        p.put("db.cloud.host", "127.0.0.1");
+        when(statsCollector.getDbProperties()).thenReturn(p);
+
+        Assert.assertTrue(statsCollector.isDbLocal());
+    }
+    @Test
+    public void testIsDbSymbolicLocal() {
+        Properties p = new Properties();
+        p.put("db.cloud.host", "localhost");
+        when(statsCollector.getDbProperties()).thenReturn(p);
+
+        Assert.assertTrue(statsCollector.isDbLocal());
+    }
+    @Test
+    public void testIsDbOnSameIp() {
+        Properties p = new Properties();
+        p.put("db.cloud.host", "10.10.10.10");
+        p.put("cluster.node.IP", "10.10.10.10");
+        when(statsCollector.getDbProperties()).thenReturn(p);
+
+        Assert.assertTrue(statsCollector.isDbLocal());
+    }
+    @Test
+    public void testIsDbNotLocal() {
+        Properties p = new Properties();
+        p.put("db.cloud.host", "10.10.10.11");
+        p.put("cluster.node.IP", "10.10.10.10");
+        when(statsCollector.getDbProperties()).thenReturn(p);
+
+        Assert.assertFalse(statsCollector.isDbLocal());
+    }
 }
diff --git a/test/integration/smoke/test_metrics_api.py b/test/integration/smoke/test_metrics_api.py
index 7cd09b44c7..e870dadee8 100644
--- a/test/integration/smoke/test_metrics_api.py
+++ b/test/integration/smoke/test_metrics_api.py
@@ -30,42 +30,44 @@ _multiprocess_shared_ = True
 
 class TestMetrics(cloudstackTestCase):
 
-    def setUp(self):
-        self.apiclient = self.testClient.getApiClient()
-        self.hypervisor = self.testClient.getHypervisorInfo()
-        self.dbclient = self.testClient.getDbConnection()
-        self.services = self.testClient.getParsedTestDataConfig()
-        self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
-        self.pod = get_pod(self.apiclient, self.zone.id)
-        self.host = list_hosts(self.apiclient,
-            zoneid=self.zone.id,
-            type='Routing')[0]
-        self.cluster = self.apiclient.listClusters(listClusters.listClustersCmd())[0]
-        self.disk_offering = DiskOffering.create(
-                                    self.apiclient,
-                                    self.services["disk_offering"]
-                                    )
-        self.service_offering = ServiceOffering.create(
-            self.apiclient,
-            self.services["service_offering"]
+    @classmethod
+    def setUpClass(cls):
+        cls.apiclient = cls.testClient.getApiClient()
+        cls.hypervisor = cls.testClient.getHypervisorInfo()
+        cls.dbclient = cls.testClient.getDbConnection()
+        cls.services = cls.testClient.getParsedTestDataConfig()
+        cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+        cls.pod = get_pod(cls.apiclient, cls.zone.id)
+        cls.host = list_hosts(cls.apiclient,
+                               zoneid=cls.zone.id,
+                               type='Routing')[0]
+        cls.cluster = cls.apiclient.listClusters(listClusters.listClustersCmd())[0]
+        cls._cleanup = []
+        cls.disk_offering = DiskOffering.create(
+            cls.apiclient,
+            cls.services["disk_offering"]
         )
-        self.template = get_test_template(
-            self.apiclient,
-            self.zone.id,
-            self.hypervisor
+        cls._cleanup.append(cls.disk_offering)
+        cls.service_offering = ServiceOffering.create(
+            cls.apiclient,
+            cls.services["service_offering"]
+        )
+        cls.template = get_test_template(
+            cls.apiclient,
+            cls.zone.id,
+            cls.hypervisor
         )
+        cls._cleanup.append(cls.service_offering)
 
+    @classmethod
+    def tearDownClass(cls):
+        super(TestMetrics, cls).tearDownClass()
+
+    def setUp(self):
         self.cleanup = []
-        self.cleanup.append(self.disk_offering)
-        self.cleanup.append(self.service_offering)
 
     def tearDown(self):
-        try:
-            #Clean up
-            cleanup_resources(self.apiclient, self.cleanup)
-
-        except Exception as e:
-            raise Exception("Warning: Exception during cleanup : %s" % e)
+        super(TestMetrics, self).tearDown();
 
     @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
     def test_list_hosts_metrics(self):
@@ -79,6 +81,8 @@ class TestMetrics(cloudstackTestCase):
         self.assertEqual(host_metric.cpuallocated, self.host.cpuallocated)
         self.assertEqual(host_metric.memoryallocated, self.host.memoryallocated)
 
+        return
+
     @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
     def test_list_clusters_metrics(self):
 
@@ -94,6 +98,8 @@ class TestMetrics(cloudstackTestCase):
         self.assertTrue(hasattr(cluster_metric, 'memoryused'))
         self.assertTrue(hasattr(cluster_metric, 'memorymaxdeviation'))
 
+        return
+
     @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
     def test_list_zones_metrics(self):
         cmd = listZonesMetrics.listZonesMetricsCmd()
@@ -109,6 +115,8 @@ class TestMetrics(cloudstackTestCase):
         self.assertTrue(hasattr(zone_metrics, 'memorymaxdeviation'))
         self.assertTrue(hasattr(zone_metrics, 'memoryused'))
 
+        return
+
     @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
     def test_list_vms_metrics(self):
         #deploy VM
@@ -152,6 +160,8 @@ class TestMetrics(cloudstackTestCase):
         self.assertEqual(sp_metrics.disksizeallocated, sp.disksizeallocated)
         self.assertEqual(sp_metrics.state, sp.state)
 
+        return
+
     @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
     def test_list_volumes_metrics(self):
         volume = Volume.create(
@@ -208,3 +218,162 @@ class TestMetrics(cloudstackTestCase):
 
         self.assertTrue(hasattr(li, 'systemvms'))
         self.assertTrue(hasattr(li, 'cpusockets'))
+
+        return
+
+    @attr(tags = ["advanced", "advancedns", "smoke", "basic", "bla"], required_hardware="false")
+    def test_list_management_server_metrics(self):
+        cmd = listManagementServersMetrics.listManagementServersMetricsCmd()
+        listMSMs = self.apiclient.listManagementServersMetrics(cmd)
+        cmd = listManagementServers.listManagementServersCmd()
+        listMSs= self.apiclient.listManagementServers(cmd)
+
+        self.assertEqual(len(listMSMs), len(listMSs))
+
+        metrics = listMSMs[0]
+        self.assertTrue(hasattr(metrics, 'availableprocessors'))
+        self.assertTrue(isinstance(metrics.availableprocessors, int))
+        self.assertTrue(hasattr(metrics, 'agentcount'))
+        self.assertTrue(isinstance(metrics.agentcount, int))
+        self.assertTrue(hasattr(metrics, 'sessions'))
+        self.assertTrue(isinstance(metrics.sessions, int))
+
+        self.assertTrue(hasattr(metrics, 'heapmemoryused'))
+        self.assertTrue(isinstance(metrics.heapmemoryused, int))
+        self.assertTrue(hasattr(metrics, 'heapmemorytotal'))
+        self.assertTrue(isinstance(metrics.heapmemorytotal, int))
+        self.assertTrue(metrics.heapmemoryused <= metrics.heapmemorytotal)
+
+        self.assertTrue(hasattr(metrics, 'threadsblockedcount'))
+        self.assertTrue(isinstance(metrics.threadsblockedcount, int))
+        self.assertTrue(hasattr(metrics, 'threadsdaemoncount'))
+        self.assertTrue(isinstance(metrics.threadsdaemoncount, int))
+        self.assertTrue(hasattr(metrics, 'threadsrunnablecount'))
+        self.assertTrue(isinstance(metrics.threadsrunnablecount, int))
+        self.assertTrue(hasattr(metrics, 'threadsteminatedcount'))
+        self.assertTrue(isinstance(metrics.threadsteminatedcount, int))
+        self.assertTrue(hasattr(metrics, 'threadstotalcount'))
+        self.assertTrue(isinstance(metrics.threadstotalcount, int))
+        self.assertTrue(hasattr(metrics, 'threadswaitingcount'))
+        self.assertTrue(isinstance(metrics.threadswaitingcount, int))
+        self.assertTrue(metrics.threadsblockedcount   <= metrics.threadstotalcount)
+        self.assertTrue(metrics.threadsdaemoncount    <= metrics.threadstotalcount)
+        self.assertTrue(metrics.threadsrunnablecount  <= metrics.threadstotalcount)
+        self.assertTrue(metrics.threadsteminatedcount <= metrics.threadstotalcount)
+        self.assertTrue(metrics.threadswaitingcount   <= metrics.threadstotalcount)
+
+        self.assertTrue(hasattr(metrics, 'systemmemorytotal'))
+        self.assertTrue(isinstance(metrics.systemmemorytotal, str))
+        self.assertTrue(hasattr(metrics, 'systemmemoryfree'))
+        self.assertTrue(isinstance(metrics.systemmemoryfree, str))
+        self.assertTrue(hasattr(metrics, 'systemmemoryvirtualsize'))
+        self.assertTrue(isinstance(metrics.systemmemoryvirtualsize, str))
+
+        self.assertTrue(hasattr(metrics, 'loginfo'))
+        self.assertTrue(isinstance(metrics.loginfo, str))
+        self.assertTrue(hasattr(metrics, 'systemtotalcpucycles'))
+        self.assertTrue(isinstance(metrics.systemtotalcpucycles, float))
+        self.assertTrue(hasattr(metrics, 'systemloadaverages'))
+        self.assertTrue(isinstance(metrics.systemloadaverages, list))
+        self.assertEqual(len(metrics.systemloadaverages), 3)
+        self.assertTrue(hasattr(metrics, 'systemcycleusage'))
+        self.assertTrue(isinstance(metrics.systemcycleusage, list))
+        self.assertEqual(len(metrics.systemcycleusage), 3)
+        self.assertTrue(hasattr(metrics, 'dbislocal'))
+        self.assertTrue(isinstance(metrics.dbislocal, bool))
+        self.assertTrue(hasattr(metrics, 'usageislocal'))
+        self.assertTrue(isinstance(metrics.usageislocal, bool))
+        self.assertTrue(hasattr(metrics, 'collectiontime'))
+        self.assertTrue(isinstance(metrics.collectiontime, str))
+        self.assertTrue(self.valid_date(metrics.collectiontime))
+        self.assertTrue(hasattr(metrics, 'id'))
+        self.assertTrue(isinstance(metrics.id, str))
+        self.assertTrue(hasattr(metrics, 'name'))
+        self.assertTrue(isinstance(metrics.name, str))
+        self.assertTrue(hasattr(metrics, 'state'))
+        self.assertEqual(metrics.state, 'Up')
+        self.assertTrue(hasattr(metrics, 'version'))
+        self.assertTrue(isinstance(metrics.version, str))
+        self.assertTrue(hasattr(metrics, 'javadistribution'))
+        self.assertTrue(isinstance(metrics.javadistribution, str))
+        self.assertTrue(hasattr(metrics, 'javaversion'))
+        self.assertTrue(isinstance(metrics.javaversion, str))
+        self.assertTrue(hasattr(metrics, 'osdistribution'))
+        self.assertTrue(isinstance(metrics.osdistribution, str))
+        self.assertTrue(hasattr(metrics, 'lastserverstart'))
+        self.assertTrue(isinstance(metrics.lastserverstart, str))
+        self.assertTrue(self.valid_date(metrics.lastserverstart))
+        if hasattr(metrics, 'lastserverstop') and metrics.lastserverstop:
+            self.debug(f"=== lastserverstop {metrics.lastserverstop} ===")
+            self.assertTrue(isinstance(metrics.lastserverstop, str))
+            self.assertTrue(self.valid_date(metrics.lastserverstop))
+        self.assertTrue(hasattr(metrics, 'lastboottime'))
+        self.assertTrue(isinstance(metrics.lastboottime, str))
+        self.assertTrue(self.valid_date(metrics.lastboottime))
+
+        return
+
+    @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+    def test_list_usage_server_metrics(self):
+        cmd = listUsageServerMetrics.listUsageServerMetricsCmd()
+        metrics = self.apiclient.listUsageServerMetrics(cmd)
+
+        self.assertTrue(hasattr(metrics,'collectiontime'))
+        self.assertTrue(isinstance(metrics.collectiontime, str))
+        self.assertTrue(self.valid_date(metrics.collectiontime))
+        self.assertTrue(hasattr(metrics, 'hostname'))
+        self.assertTrue(isinstance(metrics.hostname, str))
+        if hasattr(metrics, 'lastheartbeat') and metrics.lastheartbeat :
+            self.debug(f"=== lastheartbeat {metrics.lastheartbeat} ===")
+            self.assertTrue(isinstance(metrics.lastheartbeat, str))
+            self.assertTrue(self.valid_date(metrics.lastheartbeat))
+        if hasattr(metrics, 'lastsuccessfuljob') and metrics.lastsuccessfuljob:
+            self.debug(f"=== lastsuccessfuljob {metrics.lastsuccessfuljob} ===")
+            self.assertTrue(isinstance(metrics.lastsuccessfuljob, str))
+            self.assertTrue(self.valid_date(metrics.lastsuccessfuljob))
+        self.assertTrue(hasattr(metrics, 'state'))
+        self.assertTrue(metrics.state == 'Up' or metrics.state == 'Down')
+
+        return
+
+    @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+    def test_list_db_metrics(self):
+        cmd = listDbMetrics.listDbMetricsCmd()
+        metrics = self.apiclient.listDbMetrics(cmd)
+
+        self.assertTrue(hasattr(metrics,'collectiontime'))
+        self.assertTrue(isinstance(metrics.collectiontime, str))
+        self.assertTrue(self.valid_date(metrics.collectiontime))
+        self.assertTrue(hasattr(metrics, 'connections'))
+        self.assertTrue(isinstance(metrics.connections, int))
+
+        cmd = listConfigurations.listConfigurationsCmd()
+        cmd.name = 'database.server.stats.retention'
+        configuration = self.apiclient.listConfigurations(cmd)
+        retention = int(configuration[0].value)
+        self.assertTrue(hasattr(metrics, 'dbloadaverages'))
+        self.assertTrue(isinstance(metrics.dbloadaverages, list))
+        self.assertTrue(len(metrics.dbloadaverages) <= retention)
+
+        self.assertTrue(hasattr(metrics, 'hostname'))
+        self.assertTrue(isinstance(metrics.hostname, str))
+        self.assertTrue(hasattr(metrics, 'queries'))
+        self.assertTrue(isinstance(metrics.queries, int))
+        self.assertTrue(hasattr(metrics, 'replicas'))
+        self.assertTrue(isinstance(metrics.replicas, list))
+        self.assertTrue(hasattr(metrics, 'uptime'))
+        self.assertTrue(isinstance(metrics.uptime, int))
+        self.assertTrue(hasattr(metrics, 'version'))
+        self.assertTrue(isinstance(metrics.version, str))
+        self.assertTrue(hasattr(metrics, 'versioncomment'))
+        self.assertTrue(isinstance(metrics.versioncomment, str))
+
+        return
+
+    def valid_date(cls, date_text):
+        try:
+            datetime.datetime.strptime(date_text, '%Y-%m-%dT%H:%M:%S%z')
+            return True
+        except ValueError:
+            return False
+
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 2fee8c8e3d..e00e7b3c2d 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -1,8 +1,32430 @@
 {
   "name": "cloudstack-ui",
   "version": "1.0.0",
-  "lockfileVersion": 1,
+  "lockfileVersion": 2,
   "requires": true,
+  "packages": {
+    "": {
+      "name": "cloudstack-ui",
+      "version": "1.0.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@fortawesome/fontawesome-svg-core": "^1.2.34",
+        "@fortawesome/free-brands-svg-icons": "^5.15.2",
+        "@fortawesome/free-solid-svg-icons": "^5.15.2",
+        "@fortawesome/vue-fontawesome": "^2.0.2",
+        "ant-design-vue": "~1.7.3",
+        "antd-theme-webpack-plugin": "^1.3.9",
+        "axios": "^0.21.1",
+        "babel-plugin-require-context-hook": "^1.0.0",
+        "core-js": "^3.6.5",
+        "enquire.js": "^2.1.6",
+        "js-cookie": "^2.2.1",
+        "lodash": "^4.17.15",
+        "md5": "^2.2.1",
+        "moment": "^2.26.0",
+        "npm-check-updates": "^6.0.1",
+        "nprogress": "^0.2.0",
+        "viser-vue": "^2.4.8",
+        "vue": "^2.6.12",
+        "vue-clipboard2": "^0.3.1",
+        "vue-cropper": "0.5.6",
+        "vue-i18n": "^8.22.4",
+        "vue-ls": "^3.2.2",
+        "vue-router": "^3.5.1",
+        "vue-svg-component-runtime": "^1.0.1",
+        "vuedraggable": "^2.24.3",
+        "vuex": "^3.6.2"
+      },
+      "devDependencies": {
+        "@vue/cli": "^4.4.1",
+        "@vue/cli-plugin-babel": "^4.4.1",
+        "@vue/cli-plugin-eslint": "^4.4.1",
+        "@vue/cli-plugin-unit-jest": "^4.4.1",
+        "@vue/cli-service": "^4.4.1",
+        "@vue/eslint-config-standard": "^5.1.2",
+        "@vue/test-utils": "^1.0.3",
+        "babel-core": "7.0.0-bridge.0",
+        "babel-eslint": "^10.0.3",
+        "babel-jest": "^25.1.0",
+        "babel-plugin-import": "^1.13.0",
+        "eslint": "^6.8.0",
+        "eslint-plugin-html": "^6.0.2",
+        "eslint-plugin-import": "^2.20.2",
+        "eslint-plugin-node": "^11.1.0",
+        "eslint-plugin-promise": "^4.2.1",
+        "eslint-plugin-standard": "^4.0.1",
+        "eslint-plugin-vue": "^6.2.2",
+        "less": "^3.11.1",
+        "less-loader": "^5.0.0",
+        "node-sass": "^4.13.1",
+        "sass-loader": "^8.0.2",
+        "uglifyjs-webpack-plugin": "^2.2.0",
+        "vue-cli-plugin-i18n": "^1.0.1",
+        "vue-svg-icon-loader": "^2.1.1",
+        "vue-template-compiler": "^2.6.12",
+        "webpack": "^4.43.0"
+      }
+    },
+    "node_modules/@akryum/winattr": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@akryum/winattr/-/winattr-3.0.0.tgz",
+      "integrity": "sha512-t4WmWoGV9gyzypwG3y3JlcK2t8fKLtvzBA7xEoFTj9SMPvOuLsf13uh4ikK0RRaaa9RPPWLgFUdOyIRaQvCpwQ==",
+      "dev": true,
+      "dependencies": {
+        "fswin": "^2.17.1227"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@ant-design/colors": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz",
+      "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==",
+      "dependencies": {
+        "tinycolor2": "^1.4.1"
+      }
+    },
+    "node_modules/@ant-design/icons": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
+      "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
+    },
+    "node_modules/@ant-design/icons-vue": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-2.0.0.tgz",
+      "integrity": "sha512-2c0QQE5hL4N48k5NkPG5sdpMl9YnvyNhf0U7YkdZYDlLnspoRU7vIA0UK9eHBs6OpFLcJB6o8eJrIl2ajBskPg==",
+      "dependencies": {
+        "@ant-design/colors": "^3.1.0",
+        "babel-runtime": "^6.26.0"
+      },
+      "peerDependencies": {
+        "@ant-design/icons": "^2.0.0",
+        "vue": ">=2.5.0",
+        "vue-template-compiler": ">=2.5.0"
+      }
+    },
+    "node_modules/@antv/adjust": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz",
+      "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==",
+      "dependencies": {
+        "@antv/util": "~1.3.1"
+      }
+    },
+    "node_modules/@antv/attr": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz",
+      "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==",
+      "dependencies": {
+        "@antv/util": "~1.3.1"
+      }
+    },
+    "node_modules/@antv/component": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.9.tgz",
+      "integrity": "sha512-Knh/Nq0S8UkTfZj4SL7XizagTfXYqjFAYIqFtOmUaKpRMgccUi7p1oA7fJdNPGktkndljy6fUmCWocEeBXRS2g==",
+      "dependencies": {
+        "@antv/attr": "~0.1.2",
+        "@antv/g": "~3.3.5",
+        "@antv/util": "~1.3.1",
+        "wolfy87-eventemitter": "~5.1.0"
+      }
+    },
+    "node_modules/@antv/component/node_modules/@antv/g": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz",
+      "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==",
+      "dependencies": {
+        "@antv/gl-matrix": "~2.7.1",
+        "@antv/util": "~1.3.1",
+        "d3-ease": "~1.0.3",
+        "d3-interpolate": "~1.1.5",
+        "d3-timer": "~1.0.6",
+        "wolfy87-eventemitter": "~5.1.0"
+      }
+    },
+    "node_modules/@antv/coord": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz",
+      "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==",
+      "dependencies": {
+        "@antv/util": "~1.3.1"
+      }
+    },
+    "node_modules/@antv/g": {
+      "version": "3.4.10",
+      "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.4.10.tgz",
+      "integrity": "sha512-pKy/L1SyRBsXuujdkggqrdBA0/ciAgHiArYBdIJsxHRxCneUP01wGwHdGfDayh2+S0gcSBHynjhoEahsaZaLkw==",
+      "dependencies": {
+        "@antv/gl-matrix": "~2.7.1",
+        "@antv/util": "~1.3.1",
+        "d3-ease": "~1.0.3",
+        "d3-interpolate": "~1.1.5",
+        "d3-timer": "~1.0.6",
+        "detect-browser": "^5.1.0"
+      }
+    },
+    "node_modules/@antv/g2": {
+      "version": "3.5.17",
+      "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.17.tgz",
+      "integrity": "sha512-gOjfA6pwXYEC5mrLbvg1kA3jZI5J5T2kQeGse+iBBsNc1Vje7zs9G+BleUaI4MLXSnqwhsj/ohfkP7d+h4ArNg==",
+      "dependencies": {
+        "@antv/adjust": "~0.1.0",
+        "@antv/attr": "~0.1.2",
+        "@antv/component": "~0.3.3",
+        "@antv/coord": "~0.1.0",
+        "@antv/g": "~3.4.10",
+        "@antv/scale": "~0.1.1",
+        "@antv/util": "~1.3.1",
+        "venn.js": "~0.2.20",
+        "wolfy87-eventemitter": "~5.1.0"
+      }
+    },
+    "node_modules/@antv/g2-brush": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/@antv/g2-brush/-/g2-brush-0.0.2.tgz",
+      "integrity": "sha512-7O9szwem19nmEgReXhFB8kVLRaz8J5MHvrzDSDY36YaBOaHSWRGHnvYt2KkkPqgWtHtLY1srssk4X/UmP5govA=="
+    },
+    "node_modules/@antv/g2-plugin-slider": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@antv/g2-plugin-slider/-/g2-plugin-slider-2.1.1.tgz",
+      "integrity": "sha512-nB678VEGG3FkrvkDDFADAKjLQIeXzITEYqey5oeOpbf0vT5jOa55lQDyJDZ79cK8PmU/Hz6VPeSb3CNQBA+/FQ==",
+      "peerDependencies": {
+        "@antv/g2": ">=3.2.8"
+      }
+    },
+    "node_modules/@antv/gl-matrix": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz",
+      "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q=="
+    },
+    "node_modules/@antv/scale": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.5.tgz",
+      "integrity": "sha512-7RAu4iH5+Hk21h6+aBMiDTfmLf4IibK2SWjx/+E4f4AXRpqucO+8u7IbZdFkakAWxvqhJtN3oePJuTKqOMcmlg==",
+      "dependencies": {
+        "@antv/util": "~1.3.1",
+        "fecha": "~2.3.3"
+      }
+    },
+    "node_modules/@antv/util": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz",
+      "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==",
+      "dependencies": {
+        "@antv/gl-matrix": "^2.7.1"
+      }
+    },
+    "node_modules/@apollo/federation": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/@apollo/federation/-/federation-0.17.0.tgz",
+      "integrity": "sha512-vSW/M8+SGdu5xALsA/RL37GgB+wNFZpXCyPAcg3b68c8x7uoQHgYwqwUu7D+GnAGeOpDUrNnFPdKAYW7elYkyQ==",
+      "dev": true,
+      "dependencies": {
+        "apollo-graphql": "^0.4.0",
+        "apollo-server-env": "^2.4.5",
+        "core-js": "^3.4.0",
+        "lodash.xorby": "^4.7.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "peerDependencies": {
+        "graphql": "^14.5.0 || ^15.0.0"
+      }
+    },
+    "node_modules/@apollo/federation/node_modules/apollo-graphql": {
+      "version": "0.4.5",
+      "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.4.5.tgz",
+      "integrity": "sha512-0qa7UOoq7E71kBYE7idi6mNQhHLVdMEDInWk6TNw3KsSWZE2/I68gARP84Mj+paFTO5NYuw1Dht66PVX76Cc2w==",
+      "dev": true,
+      "dependencies": {
+        "apollo-env": "^0.6.5",
+        "lodash.sortby": "^4.7.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "peerDependencies": {
+        "graphql": "^14.2.1"
+      }
+    },
+    "node_modules/@apollo/protobufjs": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.0.4.tgz",
+      "integrity": "sha512-EE3zx+/D/wur/JiLp6VCiw1iYdyy1lCJMf8CGPkLeDt5QJrN4N8tKFx33Ah4V30AUQzMk7Uz4IXKZ1LOj124gA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/long": "^4.0.0",
+        "@types/node": "^10.1.0",
+        "long": "^4.0.0"
+      },
+      "bin": {
+        "apollo-pbjs": "bin/pbjs",
+        "apollo-pbts": "bin/pbts"
+      }
+    },
+    "node_modules/@apollo/protobufjs/node_modules/@types/node": {
+      "version": "10.17.28",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.28.tgz",
+      "integrity": "sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==",
+      "dev": true
+    },
+    "node_modules/@apollographql/apollo-tools": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.4.8.tgz",
+      "integrity": "sha512-W2+HB8Y7ifowcf3YyPHgDI05izyRtOeZ4MqIr7LbTArtmJ0ZHULWpn84SGMW7NAvTV1tFExpHlveHhnXuJfuGA==",
+      "dev": true,
+      "dependencies": {
+        "apollo-env": "^0.6.5"
+      },
+      "engines": {
+        "node": ">=8",
+        "npm": ">=6"
+      }
+    },
+    "node_modules/@apollographql/graphql-language-service-interface": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-interface/-/graphql-language-service-interface-2.0.2.tgz",
+      "integrity": "sha512-28wePK0hlIVjgmvMXMAUq8qRSjz9O+6lqFp4PzOTHtfJfSsjVe9EfjF98zTpHsTgT3HcOxmbqDZZy8jlXtOqEA==",
+      "dev": true,
+      "dependencies": {
+        "@apollographql/graphql-language-service-parser": "^2.0.0",
+        "@apollographql/graphql-language-service-types": "^2.0.0",
+        "@apollographql/graphql-language-service-utils": "^2.0.2"
+      },
+      "peerDependencies": {
+        "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
+      }
+    },
+    "node_modules/@apollographql/graphql-language-service-parser": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-parser/-/graphql-language-service-parser-2.0.2.tgz",
+      "integrity": "sha512-rpTPrEJu1PMaRQxz5P8BZWsixNNhYloS0H0dwTxNBuE3qctbARvR7o8UCKLsmKgTbo+cz3T3a6IAsWlkHgMWGg==",
+      "dev": true,
+      "dependencies": {
+        "@apollographql/graphql-language-service-types": "^2.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
+      }
+    },
+    "node_modules/@apollographql/graphql-language-service-types": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-types/-/graphql-language-service-types-2.0.2.tgz",
+      "integrity": "sha512-vE+Dz8pG+Xa1Z2nMl82LoO66lQ6JqBUjaXqLDvS3eMjvA3N4hf+YUDOWfPdNZ0zjhHhHXzUIIZCkax6bXfFbzQ==",
+      "dev": true,
+      "peerDependencies": {
+        "graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
+      }
+    },
+    "node_modules/@apollographql/graphql-language-service-utils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@apollographql/graphql-language-service-utils/-/graphql-language-service-utils-2.0.2.tgz",
+      "integrity": "sha512-fDj5rWlTi/czvUS5t7V7I45Ai6bOO3Z7JARYj21Y2xxfbRGtJi6h8FvLX0N/EbzQgo/fiZc/HAhtfwn+OCjD7A==",
+      "dev": true,
+      "dependencies": {
+        "@apollographql/graphql-language-service-types": "^2.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
+      }
+    },
+    "node_modules/@apollographql/graphql-playground-html": {
+      "version": "1.6.26",
+      "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.26.tgz",
+      "integrity": "sha512-XAwXOIab51QyhBxnxySdK3nuMEUohhDsHQ5Rbco/V1vjlP75zZ0ZLHD9dTpXTN8uxKxopb2lUvJTq+M4g2Q0HQ==",
+      "dev": true,
+      "dependencies": {
+        "xss": "^1.0.6"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+      "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/highlight": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz",
+      "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==",
+      "dev": true,
+      "dependencies": {
+        "browserslist": "^4.12.0",
+        "invariant": "^2.2.4",
+        "semver": "^5.5.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.0.tgz",
+      "integrity": "sha512-mkLq8nwaXmDtFmRkQ8ED/eA2CnVw4zr7dCztKalZXBvdK5EeNUAesrrwUqjQEzFgomJssayzB0aqlOsP1vGLqg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.11.0",
+        "@babel/helper-module-transforms": "^7.11.0",
+        "@babel/helpers": "^7.10.4",
+        "@babel/parser": "^7.11.0",
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.11.0",
+        "@babel/types": "^7.11.0",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.1",
+        "json5": "^2.1.2",
+        "lodash": "^4.17.19",
+        "resolve": "^1.3.2",
+        "semver": "^5.4.1",
+        "source-map": "^0.5.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@babel/core/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@babel/core/node_modules/resolve": {
+      "version": "1.17.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
+      "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
+      "dev": true,
+      "dependencies": {
+        "path-parse": "^1.0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/@babel/core/node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz",
+      "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.11.0",
+        "jsesc": "^2.5.1",
+        "source-map": "^0.5.0"
+      }
+    },
+    "node_modules/@babel/generator/node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz",
+      "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz",
+      "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-explode-assignable-expression": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz",
+      "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.10.4",
+        "browserslist": "^4.12.0",
+        "invariant": "^2.2.4",
+        "levenary": "^1.1.1",
+        "semver": "^5.5.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz",
+      "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/helper-member-expression-to-functions": "^7.10.5",
+        "@babel/helper-optimise-call-expression": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-replace-supers": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-regexp-features-plugin": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz",
+      "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.10.4",
+        "@babel/helper-regex": "^7.10.4",
+        "regexpu-core": "^4.7.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-define-map": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz",
+      "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/types": "^7.10.5",
+        "lodash": "^4.17.19"
+      }
+    },
+    "node_modules/@babel/helper-explode-assignable-expression": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz",
+      "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-function-name": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+      "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-get-function-arity": "^7.10.4",
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-get-function-arity": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+      "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-hoist-variables": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz",
+      "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-member-expression-to-functions": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz",
+      "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.11.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz",
+      "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz",
+      "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.10.4",
+        "@babel/helper-replace-supers": "^7.10.4",
+        "@babel/helper-simple-access": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.11.0",
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.11.0",
+        "lodash": "^4.17.19"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
+      "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
+      "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
+      "dev": true
+    },
+    "node_modules/@babel/helper-regex": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz",
+      "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.19"
+      }
+    },
+    "node_modules/@babel/helper-remap-async-to-generator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz",
+      "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.10.4",
+        "@babel/helper-wrap-function": "^7.10.4",
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz",
+      "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-member-expression-to-functions": "^7.10.4",
+        "@babel/helper-optimise-call-expression": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz",
+      "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz",
+      "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.11.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+      "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.11.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+      "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+      "dev": true
+    },
+    "node_modules/@babel/helper-wrap-function": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz",
+      "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz",
+      "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+      "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.10.4",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz",
+      "integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==",
+      "dev": true,
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-async-generator-functions": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz",
+      "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-remap-async-to-generator": "^7.10.4",
+        "@babel/plugin-syntax-async-generators": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-class-properties": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz",
+      "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-decorators": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz",
+      "integrity": "sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.10.5",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-decorators": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-dynamic-import": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz",
+      "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-export-namespace-from": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz",
+      "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-json-strings": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz",
+      "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-json-strings": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-logical-assignment-operators": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz",
+      "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz",
+      "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-object-rest-spread": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz",
+      "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+        "@babel/plugin-transform-parameters": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-optional-catch-binding": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz",
+      "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-optional-chaining": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz",
+      "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-private-methods": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz",
+      "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-unicode-property-regex": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz",
+      "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz",
+      "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-decorators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz",
+      "integrity": "sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-dynamic-import": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+      "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-export-namespace-from": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
+      "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-flow": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.4.tgz",
+      "integrity": "sha512-yxQsX1dJixF4qEEdzVbst3SZQ58Nrooz8NV9Z9GL4byTE25BvJgl5lf0RECUf0fh28rZBb/RYTWn/eeKwCMrZQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz",
+      "integrity": "sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz",
+      "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz",
+      "integrity": "sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-arrow-functions": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz",
+      "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-async-to-generator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz",
+      "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-remap-async-to-generator": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoped-functions": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz",
+      "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoping": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz",
+      "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-classes": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz",
+      "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.10.4",
+        "@babel/helper-define-map": "^7.10.4",
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/helper-optimise-call-expression": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-replace-supers": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.10.4",
+        "globals": "^11.1.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-computed-properties": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz",
+      "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-destructuring": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz",
+      "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-dotall-regex": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz",
+      "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-duplicate-keys": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz",
+      "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-exponentiation-operator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz",
+      "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-flow-strip-types": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.4.tgz",
+      "integrity": "sha512-XTadyuqNst88UWBTdLjM+wEY7BFnY2sYtPyAidfC7M/QaZnSuIZpMvLxqGT7phAcnGyWh/XQFLKcGf04CnvxSQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-flow": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-for-of": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz",
+      "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-function-name": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz",
+      "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-literals": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz",
+      "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-member-expression-literals": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz",
+      "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-amd": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz",
+      "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.10.5",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "babel-plugin-dynamic-import-node": "^2.3.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-commonjs": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz",
+      "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-simple-access": "^7.10.4",
+        "babel-plugin-dynamic-import-node": "^2.3.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-systemjs": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz",
+      "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-hoist-variables": "^7.10.4",
+        "@babel/helper-module-transforms": "^7.10.5",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "babel-plugin-dynamic-import-node": "^2.3.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-umd": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz",
+      "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz",
+      "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-new-target": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz",
+      "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-object-super": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz",
+      "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-replace-supers": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-parameters": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz",
+      "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-get-function-arity": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-property-literals": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz",
+      "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-regenerator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz",
+      "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==",
+      "dev": true,
+      "dependencies": {
+        "regenerator-transform": "^0.14.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-reserved-words": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz",
+      "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-runtime": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz",
+      "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "resolve": "^1.8.1",
+        "semver": "^5.5.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-runtime/node_modules/resolve": {
+      "version": "1.17.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
+      "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
+      "dev": true,
+      "dependencies": {
+        "path-parse": "^1.0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/@babel/plugin-transform-shorthand-properties": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz",
+      "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-spread": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz",
+      "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-sticky-regex": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz",
+      "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-regex": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-template-literals": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz",
+      "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typeof-symbol": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz",
+      "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz",
+      "integrity": "sha512-edJsNzTtvb3MaXQwj8403B7mZoGu9ElDJQZOKjGUnvilquxBA3IQoEIOvkX/1O8xfAsnHS/oQhe2w/IXrr+w0w==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.10.5",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-typescript": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-unicode-escapes": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz",
+      "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-unicode-regex": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz",
+      "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-env": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz",
+      "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.11.0",
+        "@babel/helper-compilation-targets": "^7.10.4",
+        "@babel/helper-module-imports": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-proposal-async-generator-functions": "^7.10.4",
+        "@babel/plugin-proposal-class-properties": "^7.10.4",
+        "@babel/plugin-proposal-dynamic-import": "^7.10.4",
+        "@babel/plugin-proposal-export-namespace-from": "^7.10.4",
+        "@babel/plugin-proposal-json-strings": "^7.10.4",
+        "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0",
+        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
+        "@babel/plugin-proposal-numeric-separator": "^7.10.4",
+        "@babel/plugin-proposal-object-rest-spread": "^7.11.0",
+        "@babel/plugin-proposal-optional-catch-binding": "^7.10.4",
+        "@babel/plugin-proposal-optional-chaining": "^7.11.0",
+        "@babel/plugin-proposal-private-methods": "^7.10.4",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.10.4",
+        "@babel/plugin-syntax-async-generators": "^7.8.0",
+        "@babel/plugin-syntax-class-properties": "^7.10.4",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.0",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.0",
+        "@babel/plugin-syntax-top-level-await": "^7.10.4",
+        "@babel/plugin-transform-arrow-functions": "^7.10.4",
+        "@babel/plugin-transform-async-to-generator": "^7.10.4",
+        "@babel/plugin-transform-block-scoped-functions": "^7.10.4",
+        "@babel/plugin-transform-block-scoping": "^7.10.4",
+        "@babel/plugin-transform-classes": "^7.10.4",
+        "@babel/plugin-transform-computed-properties": "^7.10.4",
+        "@babel/plugin-transform-destructuring": "^7.10.4",
+        "@babel/plugin-transform-dotall-regex": "^7.10.4",
+        "@babel/plugin-transform-duplicate-keys": "^7.10.4",
+        "@babel/plugin-transform-exponentiation-operator": "^7.10.4",
+        "@babel/plugin-transform-for-of": "^7.10.4",
+        "@babel/plugin-transform-function-name": "^7.10.4",
+        "@babel/plugin-transform-literals": "^7.10.4",
+        "@babel/plugin-transform-member-expression-literals": "^7.10.4",
+        "@babel/plugin-transform-modules-amd": "^7.10.4",
+        "@babel/plugin-transform-modules-commonjs": "^7.10.4",
+        "@babel/plugin-transform-modules-systemjs": "^7.10.4",
+        "@babel/plugin-transform-modules-umd": "^7.10.4",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4",
+        "@babel/plugin-transform-new-target": "^7.10.4",
+        "@babel/plugin-transform-object-super": "^7.10.4",
+        "@babel/plugin-transform-parameters": "^7.10.4",
+        "@babel/plugin-transform-property-literals": "^7.10.4",
+        "@babel/plugin-transform-regenerator": "^7.10.4",
+        "@babel/plugin-transform-reserved-words": "^7.10.4",
+        "@babel/plugin-transform-shorthand-properties": "^7.10.4",
+        "@babel/plugin-transform-spread": "^7.11.0",
+        "@babel/plugin-transform-sticky-regex": "^7.10.4",
+        "@babel/plugin-transform-template-literals": "^7.10.4",
+        "@babel/plugin-transform-typeof-symbol": "^7.10.4",
+        "@babel/plugin-transform-unicode-escapes": "^7.10.4",
+        "@babel/plugin-transform-unicode-regex": "^7.10.4",
+        "@babel/preset-modules": "^0.1.3",
+        "@babel/types": "^7.11.0",
+        "browserslist": "^4.12.0",
+        "core-js-compat": "^3.6.2",
+        "invariant": "^2.2.2",
+        "levenary": "^1.1.1",
+        "semver": "^5.5.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-flow": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.10.4.tgz",
+      "integrity": "sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-transform-flow-strip-types": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-modules": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz",
+      "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
+        "@babel/plugin-transform-dotall-regex": "^7.4.4",
+        "@babel/types": "^7.4.4",
+        "esutils": "^2.0.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-typescript": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz",
+      "integrity": "sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-transform-typescript": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/register": {
+      "version": "7.10.5",
+      "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.10.5.tgz",
+      "integrity": "sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw==",
+      "dev": true,
+      "dependencies": {
+        "find-cache-dir": "^2.0.0",
+        "lodash": "^4.17.19",
+        "make-dir": "^2.1.0",
+        "pirates": "^4.0.0",
+        "source-map-support": "^0.5.16"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/register/node_modules/source-map-support": {
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.0.tgz",
+      "integrity": "sha512-qArkXsjJq7H+T86WrIFV0Fnu/tNOkZ4cgXmjkzAu3b/58D5mFIO8JH/y77t7C9q0OdDRdh9s7Ue5GasYssxtXw==",
+      "dev": true,
+      "dependencies": {
+        "regenerator-runtime": "^0.13.4"
+      }
+    },
+    "node_modules/@babel/runtime/node_modules/regenerator-runtime": {
+      "version": "0.13.7",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+      "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
+      "dev": true
+    },
+    "node_modules/@babel/template": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
+      "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/parser": "^7.10.4",
+        "@babel/types": "^7.10.4"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz",
+      "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.11.0",
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.11.0",
+        "@babel/parser": "^7.11.0",
+        "@babel/types": "^7.11.0",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0",
+        "lodash": "^4.17.19"
+      }
+    },
+    "node_modules/@babel/traverse/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@babel/traverse/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@babel/types": {
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
+      "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.10.4",
+        "lodash": "^4.17.19",
+        "to-fast-properties": "^2.0.0"
+      }
+    },
+    "node_modules/@endemolshinegroup/cosmiconfig-typescript-loader": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.2.tgz",
+      "integrity": "sha512-ZHkXKq2XFFmAUdmSZrmqUSIrRM4O9gtkdpxMmV+LQl7kScUnbo6pMnXu6+FTDgZ12aW6SDoZoOJfS56WD+Eu6A==",
+      "dev": true,
+      "dependencies": {
+        "lodash.get": "^4",
+        "make-error": "^1",
+        "ts-node": "^8",
+        "tslib": "^1"
+      },
+      "engines": {
+        "node": ">=8.0.0",
+        "yarn": ">=1.3.0"
+      },
+      "peerDependencies": {
+        "cosmiconfig": ">=5 < 6"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-common-types": {
+      "version": "0.2.34",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.34.tgz",
+      "integrity": "sha512-XcIn3iYbTEzGIxD0/dY5+4f019jIcEIWBiHc3KrmK/ROahwxmZ/s+tdj97p/5K0klz4zZUiMfUlYP0ajhSJjmA==",
+      "hasInstallScript": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-svg-core": {
+      "version": "1.2.34",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.34.tgz",
+      "integrity": "sha512-0KNN0nc5eIzaJxlv43QcDmTkDY1CqeN6J7OCGSs+fwGPdtv0yOQqRjieopBCmw+yd7uD3N2HeNL3Zm5isDleLg==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "^0.2.34"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-brands-svg-icons": {
+      "version": "5.15.2",
+      "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.2.tgz",
+      "integrity": "sha512-YPlVjE1cEO+OJ9I9ay3TQ3I88+XkxMTYwnnddqAboxLhPNGncsHV0DjWOVLCyuAY66yPfyndWwVn4v7vuqsO1g==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "^0.2.34"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-solid-svg-icons": {
+      "version": "5.15.2",
+      "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.2.tgz",
+      "integrity": "sha512-ZfCU+QjaFsdNZmOGmfqEWhzI3JOe37x5dF4kz9GeXvKn/sTxhqMtZ7mh3lBf76SvcYY5/GKFuyG7p1r4iWMQqw==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "^0.2.34"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/vue-fontawesome": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-2.0.2.tgz",
+      "integrity": "sha512-ecpKSBUWXsxRJVi/dbOds4tkKwEcBQ1JSDZFzE2jTFpF8xIh3OgTX8POIor6bOltjibr3cdEyvnDjecMwUmxhQ==",
+      "peerDependencies": {
+        "@fortawesome/fontawesome-svg-core": ">= 1.2.0 < 1.3",
+        "vue": "~2"
+      }
+    },
+    "node_modules/@hapi/address": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
+      "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==",
+      "deprecated": "Moved to 'npm install @sideway/address'",
+      "dev": true
+    },
+    "node_modules/@hapi/bourne": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz",
+      "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==",
+      "deprecated": "This version has been deprecated and is no longer supported or maintained",
+      "dev": true
+    },
+    "node_modules/@hapi/hoek": {
+      "version": "8.5.1",
+      "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz",
+      "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==",
+      "deprecated": "This version has been deprecated and is no longer supported or maintained",
+      "dev": true
+    },
+    "node_modules/@hapi/joi": {
+      "version": "15.1.1",
+      "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz",
+      "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==",
+      "deprecated": "Switch to 'npm install joi'",
+      "dev": true,
+      "dependencies": {
+        "@hapi/address": "2.x.x",
+        "@hapi/bourne": "1.x.x",
+        "@hapi/hoek": "8.x.x",
+        "@hapi/topo": "3.x.x"
+      }
+    },
+    "node_modules/@hapi/topo": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz",
+      "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==",
+      "deprecated": "This version has been deprecated and is no longer supported or maintained",
+      "dev": true,
+      "dependencies": {
+        "@hapi/hoek": "^8.3.0"
+      }
+    },
+    "node_modules/@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,
+      "dependencies": {
+        "cssnano": "^4.0.0",
+        "cssnano-preset-default": "^4.0.0",
+        "postcss": "^7.0.0"
+      },
+      "peerDependencies": {
+        "webpack": "^4.0.0"
+      }
+    },
+    "node_modules/@intervolga/optimize-cssnano-plugin/node_modules/postcss": {
+      "version": "7.0.32",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
+      "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^2.4.2",
+        "source-map": "^0.6.1",
+        "supports-color": "^6.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "tidelift",
+        "url": "https://tidelift.com/funding/github/npm/postcss"
+      }
+    },
+    "node_modules/@intervolga/optimize-cssnano-plugin/node_modules/supports-color": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+      "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+      "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
+      "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/source-map": "^24.9.0",
+        "chalk": "^2.0.1",
+        "slash": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/console/node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/core": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz",
+      "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==",
+      "dev": true,
+      "dependencies": {
+        "@jest/console": "^24.7.1",
+        "@jest/reporters": "^24.9.0",
+        "@jest/test-result": "^24.9.0",
+        "@jest/transform": "^24.9.0",
+        "@jest/types": "^24.9.0",
+        "ansi-escapes": "^3.0.0",
+        "chalk": "^2.0.1",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.1.15",
+        "jest-changed-files": "^24.9.0",
+        "jest-config": "^24.9.0",
+        "jest-haste-map": "^24.9.0",
+        "jest-message-util": "^24.9.0",
+        "jest-regex-util": "^24.3.0",
+        "jest-resolve": "^24.9.0",
+        "jest-resolve-dependencies": "^24.9.0",
+        "jest-runner": "^24.9.0",
+        "jest-runtime": "^24.9.0",
+        "jest-snapshot": "^24.9.0",
+        "jest-util": "^24.9.0",
+        "jest-validate": "^24.9.0",
+        "jest-watcher": "^24.9.0",
+        "micromatch": "^3.1.10",
+        "p-each-series": "^1.0.0",
+        "realpath-native": "^1.1.0",
+        "rimraf": "^2.5.4",
+        "slash": "^2.0.0",
+        "strip-ansi": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/core/node_modules/ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@jest/core/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/core/node_modules/rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
+    "node_modules/@jest/core/node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/core/node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/environment": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz",
+      "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/fake-timers": "^24.9.0",
+        "@jest/transform": "^24.9.0",
+        "@jest/types": "^24.9.0",
+        "jest-mock": "^24.9.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/fake-timers": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz",
+      "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==",
+      "dev": true,
+      "dependencies": {
+        "@jest/types": "^24.9.0",
+        "jest-message-util": "^24.9.0",
+        "jest-mock": "^24.9.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/reporters": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz",
+      "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==",
+      "dev": true,
+      "dependencies": {
+        "@jest/environment": "^24.9.0",
+        "@jest/test-result": "^24.9.0",
+        "@jest/transform": "^24.9.0",
+        "@jest/types": "^24.9.0",
+        "chalk": "^2.0.1",
+        "exit": "^0.1.2",
+        "glob": "^7.1.2",
+        "istanbul-lib-coverage": "^2.0.2",
+        "istanbul-lib-instrument": "^3.0.1",
+        "istanbul-lib-report": "^2.0.4",
+        "istanbul-lib-source-maps": "^3.0.1",
+        "istanbul-reports": "^2.2.6",
+        "jest-haste-map": "^24.9.0",
+        "jest-resolve": "^24.9.0",
+        "jest-runtime": "^24.9.0",
+        "jest-util": "^24.9.0",
+        "jest-worker": "^24.6.0",
+        "node-notifier": "^5.4.2",
+        "slash": "^2.0.0",
+        "source-map": "^0.6.0",
+        "string-length": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/node-notifier": {
+      "version": "5.4.3",
+      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz",
+      "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==",
+      "dev": true,
+      "dependencies": {
+        "growly": "^1.3.0",
+        "is-wsl": "^1.1.0",
+        "semver": "^5.5.0",
+        "shellwords": "^0.1.1",
+        "which": "^1.3.0"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/@jest/source-map": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz",
+      "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.1.15",
+        "source-map": "^0.6.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/source-map/node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/test-result": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz",
+      "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==",
+      "dev": true,
+      "dependencies": {
+        "@jest/console": "^24.9.0",
+        "@jest/types": "^24.9.0",
+        "@types/istanbul-lib-coverage": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/test-sequencer": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz",
+      "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==",
+      "dev": true,
+      "dependencies": {
+        "@jest/test-result": "^24.9.0",
+        "jest-haste-map": "^24.9.0",
+        "jest-runner": "^24.9.0",
+        "jest-runtime": "^24.9.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/transform": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz",
+      "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.1.0",
+        "@jest/types": "^24.9.0",
+        "babel-plugin-istanbul": "^5.1.0",
+        "chalk": "^2.0.1",
+        "convert-source-map": "^1.4.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "graceful-fs": "^4.1.15",
+        "jest-haste-map": "^24.9.0",
+        "jest-regex-util": "^24.9.0",
+        "jest-util": "^24.9.0",
+        "micromatch": "^3.1.10",
+        "pirates": "^4.0.1",
+        "realpath-native": "^1.1.0",
+        "slash": "^2.0.0",
+        "source-map": "^0.6.1",
+        "write-file-atomic": "2.4.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/write-file-atomic": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
+      "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.11",
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "node_modules/@jest/types": {
+      "version": "24.9.0",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz",
+      "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^1.1.1",
+        "@types/yargs": "^13.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@mrmlnc/readdir-enhanced": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
+      "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
+      "dev": true,
+      "dependencies": {
+        "call-me-maybe": "^1.0.1",
+        "glob-to-regexp": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
+      "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.3",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir/node_modules/@nodelib/fs.stat": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
+      "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
+      "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
+      "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.3",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@npmcli/ci-detect": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz",
+      "integrity": "sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q=="
+    },
+    "node_modules/@npmcli/git": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.3.tgz",
+      "integrity": "sha512-c/ODsV5ppjB12VDXKc6hzVNgg6ZJX/etILUn3WgF5NLAYBhQLJ3fBq6uB2jQD4OwqOzJdPT1/xA3Xh3aaWGk5w==",
+      "dependencies": {
+        "@npmcli/promise-spawn": "^1.1.0",
+        "lru-cache": "^6.0.0",
+        "mkdirp": "^1.0.3",
+        "npm-pick-manifest": "^6.0.0",
+        "promise-inflight": "^1.0.1",
+        "promise-retry": "^1.1.1",
+        "semver": "^7.3.2",
+        "unique-filename": "^1.1.1",
+        "which": "^2.0.2"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/semver": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/installed-package-contents": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.5.tgz",
+      "integrity": "sha512-aKIwguaaqb6ViwSOFytniGvLPb9SMCUm39TgM3SfUo7n0TxUMbwoXfpwyvQ4blm10lzbAwTsvjr7QZ85LvTi4A==",
+      "dependencies": {
+        "npm-bundled": "^1.1.1",
+        "npm-normalize-package-bin": "^1.0.1",
+        "read-package-json-fast": "^1.1.1",
+        "readdir-scoped-modules": "^1.1.0"
+      },
+      "bin": {
+        "installed-package-contents": "index.js"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@npmcli/move-file": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
+      "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
+      "dependencies": {
+        "mkdirp": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/promise-spawn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.2.0.tgz",
+      "integrity": "sha512-nFtqjVETliApiRdjbYwKwhlSHx2ZMagyj5b9YbNt0BWeeOVxJd47ZVE2u16vxDHyTOZvk+YLV7INwfAE9a2uow==",
+      "dependencies": {
+        "infer-owner": "^1.0.4"
+      }
+    },
+    "node_modules/@npmcli/run-script": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.4.0.tgz",
+      "integrity": "sha512-evlD0Ur2ILGyTP7FfMYi90x80bto9+nEbGjoWzdF+gmIX3HuA1nW0Ghj91JFaTJAHiXnDEEduZS24oAve/aeOA==",
+      "dependencies": {
+        "@npmcli/promise-spawn": "^1.2.0",
+        "infer-owner": "^1.0.4",
+        "node-gyp": "^6.1.0",
+        "read-package-json-fast": "^1.1.3"
+      }
+    },
+    "node_modules/@oclif/color": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/@oclif/color/-/color-0.1.2.tgz",
+      "integrity": "sha512-M9o+DOrb8l603qvgz1FogJBUGLqcMFL1aFg2ZEL0FbXJofiNTLOWIeB4faeZTLwE6dt0xH9GpCVpzksMMzGbmA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "chalk": "^3.0.0",
+        "strip-ansi": "^5.2.0",
+        "supports-color": "^5.4.0",
+        "tslib": "^1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/chalk": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+      "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/chalk/node_modules/ansi-styles": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+      "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+      "dev": true,
+      "dependencies": {
+        "@types/color-name": "^1.1.1",
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/chalk/node_modules/supports-color": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+      "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/@oclif/color/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/color/node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/command": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.7.0.tgz",
+      "integrity": "sha512-TkknFtWcZI8te0E8sW+ohiblExrLx73rIcV4KdIzDX01u+oTZWZaap51F6TSGFnR/Gey0WctaDvJhZlt4xgKdA==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/config": "^1.15.1",
+        "@oclif/errors": "^1.3.3",
+        "@oclif/parser": "^3.8.3",
+        "@oclif/plugin-help": "^3",
+        "debug": "^4.1.1",
+        "semver": "^5.6.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "peerDependencies": {
+        "@oclif/config": "^1"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/@oclif/plugin-help": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.1.0.tgz",
+      "integrity": "sha512-orSWpXGlJaX16eSjAtI8scA8QhrjQOaCSHodEx52t18JKbIVzG8jcngugyWAOB/V4jhPl0rdiVk9XFsaIIiG2g==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/command": "^1.5.20",
+        "@oclif/config": "^1.15.1",
+        "chalk": "^2.4.1",
+        "indent-string": "^4.0.0",
+        "lodash.template": "^4.4.0",
+        "string-width": "^3.0.0",
+        "strip-ansi": "^5.0.0",
+        "widest-line": "^2.0.1",
+        "wrap-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@oclif/command/node_modules/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,
+      "dependencies": {
+        "emoji-regex": "^7.0.1",
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/widest-line": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
+      "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/widest-line/node_modules/ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/widest-line/node_modules/string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/widest-line/node_modules/strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/wrap-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-4.0.0.tgz",
+      "integrity": "sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.0",
+        "string-width": "^2.1.1",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/wrap-ansi/node_modules/string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/command/node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/config": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.16.0.tgz",
+      "integrity": "sha512-vOnMPQcHokC03WBCuLipTxksTwgZcmDOnH2H0UHqndfKKN9GVDzpZTH6zaFVQBdjTME5VtRzg9A2UaNmq6OXWw==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/errors": "^1.3.3",
+        "@oclif/parser": "^3.8.0",
+        "debug": "^4.1.1",
+        "globby": "^11.0.1",
+        "is-wsl": "^2.1.1",
+        "tslib": "^1.9.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/@nodelib/fs.stat": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
+      "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/fast-glob": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
+      "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.0",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.2",
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/glob-parent": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/globby": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
+      "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.1.1",
+        "ignore": "^5.1.4",
+        "merge2": "^1.3.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/ignore": {
+      "version": "5.1.8",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+      "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/is-wsl": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/micromatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+      "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.1",
+        "picomatch": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@oclif/config/node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/config/node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/@oclif/errors": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.3.tgz",
+      "integrity": "sha512-EJR6AIOEkt/NnARNIVAskPDVtdhtO5TTNXmhDrGqMoWVsr0R6DkkLrMyq95BmHvlVWM1nduoq4fQPuCyuF2jaA==",
+      "dev": true,
+      "dependencies": {
+        "clean-stack": "^3.0.0",
+        "fs-extra": "^9.0.1",
+        "indent-string": "^4.0.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/ansi-regex": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/clean-stack": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.0.tgz",
+      "integrity": "sha512-RHxtgFvXsRQ+1AM7dlozLDY7ssmvUUh0XEnfnyhYgJTO6beNZHBogiaCwGM9Q3rFrUkYxOtsZRC0zAturg5bjg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/fs-extra": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+      "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+      "dev": true,
+      "dependencies": {
+        "at-least-node": "^1.0.0",
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/jsonfile": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
+      "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
+      "dev": true,
+      "dependencies": {
+        "universalify": "^1.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/strip-ansi": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/errors/node_modules/universalify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+      "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/@oclif/linewrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz",
+      "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==",
+      "dev": true
+    },
+    "node_modules/@oclif/parser": {
+      "version": "3.8.5",
+      "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.5.tgz",
+      "integrity": "sha512-yojzeEfmSxjjkAvMRj0KzspXlMjCfBzNRPkWw8ZwOSoNWoJn+OCS/m/S+yfV6BvAM4u2lTzX9Y5rCbrFIgkJLg==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/errors": "^1.2.2",
+        "@oclif/linewrap": "^1.0.0",
+        "chalk": "^2.4.2",
+        "tslib": "^1.9.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-autocomplete": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-autocomplete/-/plugin-autocomplete-0.2.0.tgz",
+      "integrity": "sha512-pHbaE2PH7d9lHjCgFrrQ+ZIwvY+7OAQaGoaANqDbicBNDK/Rszt4N4oGj22dJT7sCQ8a/3Eh942rjxYIq9Mi9Q==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/command": "^1.5.13",
+        "@oclif/config": "^1.13.0",
+        "chalk": "^2.4.1",
+        "cli-ux": "^5.2.1",
+        "debug": "^4.0.0",
+        "fs-extra": "^7.0.0",
+        "moment": "^2.22.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-autocomplete/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@oclif/plugin-autocomplete/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@oclif/plugin-help": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-2.2.3.tgz",
+      "integrity": "sha512-bGHUdo5e7DjPJ0vTeRBMIrfqTRDBfyR5w0MP41u0n3r7YG5p14lvMmiCXxi6WDaP2Hw5nqx3PnkAIntCKZZN7g==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/command": "^1.5.13",
+        "chalk": "^2.4.1",
+        "indent-string": "^4.0.0",
+        "lodash.template": "^4.4.0",
+        "string-width": "^3.0.0",
+        "strip-ansi": "^5.0.0",
+        "widest-line": "^2.0.1",
+        "wrap-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/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,
+      "dependencies": {
+        "emoji-regex": "^7.0.1",
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/widest-line": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
+      "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/widest-line/node_modules/ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/widest-line/node_modules/string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/widest-line/node_modules/strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/wrap-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-4.0.0.tgz",
+      "integrity": "sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.0",
+        "string-width": "^2.1.1",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/wrap-ansi/node_modules/string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-help/node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-1.2.4.tgz",
+      "integrity": "sha512-G440PCuMi/OT8b71aWkR+kCWikngGtyRjOR24sPMDbpUFV4+B3r51fz1fcqeUiiEOYqUpr0Uy/sneUe1O/NfBg==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/color": "^0.x",
+        "@oclif/command": "^1.6.0",
+        "cli-ux": "^4.9.0",
+        "fast-levenshtein": "^2.0.6",
+        "lodash": "^4.17.13"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/cli-ux": {
+      "version": "4.9.3",
+      "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.3.tgz",
+      "integrity": "sha512-/1owvF0SZ5Gn54cgrikJ0QskgTzeg30HGjkmjFoaHDJzAqFpuX1DBpFR8aLvsE1J5s9MgeYRENQK4BFwOag5VA==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/errors": "^1.2.2",
+        "@oclif/linewrap": "^1.0.0",
+        "@oclif/screen": "^1.0.3",
+        "ansi-escapes": "^3.1.0",
+        "ansi-styles": "^3.2.1",
+        "cardinal": "^2.1.1",
+        "chalk": "^2.4.1",
+        "clean-stack": "^2.0.0",
+        "extract-stack": "^1.0.0",
+        "fs-extra": "^7.0.0",
+        "hyperlinker": "^1.0.0",
+        "indent-string": "^3.2.0",
+        "is-wsl": "^1.1.0",
+        "lodash": "^4.17.11",
+        "password-prompt": "^1.0.7",
+        "semver": "^5.6.0",
+        "strip-ansi": "^5.0.0",
+        "supports-color": "^5.5.0",
+        "supports-hyperlinks": "^1.0.1",
+        "treeify": "^1.1.0",
+        "tslib": "^1.9.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/extract-stack": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-1.0.0.tgz",
+      "integrity": "sha1-uXrK+UQe6iMyUpYktzL8WhyBZfo=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/indent-string": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+      "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@oclif/plugin-not-found/node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-1.9.0.tgz",
+      "integrity": "sha512-sq31nJk/n5pH5qGDioj2Z9x6MlRUrc/kkQrfCYKRPbQM80qewSP4RcPK3/gDvDSOAWD3wLAK9oMbDQO9lqImMA==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/color": "^0.x",
+        "@oclif/command": "^1.5.12",
+        "chalk": "^2.4.2",
+        "cli-ux": "^5.2.1",
+        "debug": "^4.1.0",
+        "fs-extra": "^7.0.1",
+        "http-call": "^5.2.2",
+        "load-json-file": "^5.2.0",
+        "npm-run-path": "^3.0.0",
+        "semver": "^7.3.2",
+        "tslib": "^2.0.0",
+        "yarn": "^1.21.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/npm-run-path": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
+      "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/semver": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@oclif/plugin-plugins/node_modules/tslib": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz",
+      "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==",
+      "dev": true
+    },
+    "node_modules/@oclif/plugin-warn-if-update-available": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-1.7.0.tgz",
+      "integrity": "sha512-Nwyz3BJ8RhsfQ+OmFSsJSPIfn5YJqMrCzPh72Zgo2jqIjKIBWD8N9vTTe4kZlpeUUn77SyXFfwlBQbNCL5OEuQ==",
+      "dev": true,
+      "dependencies": {
+        "@oclif/command": "^1.5.10",
+        "@oclif/config": "^1.12.8",
+        "@oclif/errors": "^1.2.2",
+        "chalk": "^2.4.1",
+        "debug": "^4.1.0",
+        "fs-extra": "^7.0.0",
+        "http-call": "^5.2.2",
+        "lodash.template": "^4.4.0",
+        "semver": "^5.6.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@oclif/plugin-warn-if-update-available/node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/@oclif/plugin-warn-if-update-available/node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/@oclif/screen": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-1.0.4.tgz",
+      "integrity": "sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
+      "dev": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=",
+      "dev": true
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
+      "dev": true
+    },
+    "node_modules/@samverschueren/stream-to-observable": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz",
+      "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==",
+      "dev": true,
+      "dependencies": {
+        "any-observable": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@simonwep/pickr": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.7.4.tgz",
+      "integrity": "sha512-fq7jgKJT21uWGC1mARBHvvd1JYlEf93o7SuVOB4Lr0x/2UPuNC9Oe9n/GzVeg4oVtqMDfh1wIEJpsdOJEZb+3g==",
+      "dependencies": {
+        "core-js": "^3.6.5",
+        "nanopop": "^2.1.0"
+      }
+    },
+    "node_modules/@sindresorhus/is": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+      "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@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,
+      "dependencies": {
+        "chalk": "^1.1.3",
+        "error-stack-parser": "^2.0.0",
+        "string-width": "^2.0.0"
+      },
+      "peerDependencies": {
+        "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true,
+      "dependencies": {
+        "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "dependencies": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/string-width/node_modules/strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@soda/friendly-errors-webpack-plugin/node_modules/supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@soda/get-current-script": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@soda/get-current-script/-/get-current-script-1.0.2.tgz",
+      "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
+      "dev": true
+    },
+    "node_modules/@szmarczak/http-timer": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+      "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+      "dependencies": {
+        "defer-to-connect": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/accepts": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz",
+      "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/anymatch": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
+      "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
+      "dev": true
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.1.9",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz",
+      "integrity": "sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.6.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz",
+      "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz",
+      "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.0.13",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.13.tgz",
+      "integrity": "sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.3.0"
+      }
+    },
+    "node_modules/@types/body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.33",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
+      "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==",
+      "dev": true
+    },
+    "node_modules/@types/cookies": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.4.tgz",
+      "integrity": "sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==",
+      "dev": true,
+      "dependencies": {
+        "@types/connect": "*",
+        "@types/express": "*",
+        "@types/keygrip": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/cors": {
+      "version": "2.8.6",
+      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.6.tgz",
+      "integrity": "sha512-invOmosX0DqbpA+cE2yoHGUlF/blyf7nB0OGYBBiH27crcVm5NmFaZkLP4Ta1hGaesckCi5lVLlydNJCxkTOSg==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/d3-format": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.1.tgz",
+      "integrity": "sha512-KAWvReOKMDreaAwOjdfQMm0HjcUMlQG47GwqdVKgmm20vTd2pucj0a70c3gUSHrnsmo6H2AMrkBsZU2UhJLq8A=="
+    },
+    "node_modules/@types/express": {
+      "version": "4.17.7",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.7.tgz",
+      "integrity": "sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "*",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "node_modules/@types/express-serve-static-core": {
+      "version": "4.17.9",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz",
+      "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "node_modules/@types/fs-capacitor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz",
+      "integrity": "sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/glob": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+      "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+      "dev": true,
+      "dependencies": {
+        "@types/minimatch": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/graceful-fs": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz",
+      "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/graphql-upload": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/@types/graphql-upload/-/graphql-upload-8.0.3.tgz",
+      "integrity": "sha512-hmLg9pCU/GmxBscg8GCr1vmSoEmbItNNxdD5YH2TJkXm//8atjwuprB+xJBK714JG1dkxbbhp5RHX+Pz1KsCMA==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*",
+        "@types/fs-capacitor": "*",
+        "@types/koa": "*",
+        "graphql": "^14.5.3"
+      }
+    },
+    "node_modules/@types/http-assert": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.1.tgz",
+      "integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==",
+      "dev": true
+    },
+    "node_modules/@types/istanbul-lib-coverage": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
+      "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==",
+      "dev": true
+    },
+    "node_modules/@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "node_modules/@types/istanbul-reports": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz",
+      "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*",
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "node_modules/@types/jest": {
+      "version": "24.9.1",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.9.1.tgz",
+      "integrity": "sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q==",
+      "dev": true,
+      "dependencies": {
+        "jest-diff": "^24.3.0"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
+      "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
+      "dev": true
+    },
+    "node_modules/@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+      "dev": true
+    },
+    "node_modules/@types/keygrip": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz",
+      "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==",
+      "dev": true
+    },
+    "node_modules/@types/koa": {
+      "version": "2.11.3",
+      "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.3.tgz",
+      "integrity": "sha512-ABxVkrNWa4O/Jp24EYI/hRNqEVRlhB9g09p48neQp4m3xL1TJtdWk2NyNQSMCU45ejeELMQZBYyfstyVvO2H3Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/accepts": "*",
+        "@types/content-disposition": "*",
+        "@types/cookies": "*",
+        "@types/http-assert": "*",
+        "@types/keygrip": "*",
+        "@types/koa-compose": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/koa-compose": {
+      "version": "3.2.5",
+      "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz",
+      "integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/koa": "*"
+      }
+    },
+    "node_modules/@types/loader-utils": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@types/loader-utils/-/loader-utils-1.1.3.tgz",
+      "integrity": "sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/webpack": "*"
+      }
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.158",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.158.tgz",
+      "integrity": "sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w=="
+    },
+    "node_modules/@types/long": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
+      "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==",
+      "dev": true
+    },
+    "node_modules/@types/mime": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
+      "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
+      "dev": true
+    },
+    "node_modules/@types/minimatch": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+      "dev": true
+    },
+    "node_modules/@types/node": {
+      "version": "14.0.27",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
+      "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g=="
+    },
+    "node_modules/@types/node-fetch": {
+      "version": "2.5.7",
+      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz",
+      "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "form-data": "^3.0.0"
+      }
+    },
+    "node_modules/@types/node-fetch/node_modules/form-data": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
+      "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
+      "dev": true,
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
+      "dev": true
+    },
+    "node_modules/@types/q": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+      "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+      "dev": true
+    },
+    "node_modules/@types/qs": {
+      "version": "6.9.4",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz",
+      "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==",
+      "dev": true
+    },
+    "node_modules/@types/range-parser": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+      "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+      "dev": true
+    },
+    "node_modules/@types/serve-static": {
+      "version": "1.13.5",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
+      "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/express-serve-static-core": "*",
+        "@types/mime": "*"
+      }
+    },
+    "node_modules/@types/source-list-map": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
+      "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
+      "dev": true
+    },
+    "node_modules/@types/stack-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
+      "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
+      "dev": true
+    },
+    "node_modules/@types/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=",
+      "dev": true
+    },
+    "node_modules/@types/strip-json-comments": {
+      "version": "0.0.30",
+      "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz",
+      "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
+      "dev": true
+    },
+    "node_modules/@types/tapable": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
+      "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
+      "dev": true
+    },
+    "node_modules/@types/uglify-js": {
+      "version": "3.9.3",
+      "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.9.3.tgz",
+      "integrity": "sha512-KswB5C7Kwduwjj04Ykz+AjvPcfgv/37Za24O2EDzYNbwyzOo8+ydtvzUfZ5UMguiVu29Gx44l1A6VsPPcmYu9w==",
+      "dev": true,
+      "dependencies": {
+        "source-map": "^0.6.1"
+      }
+    },
+    "node_modules/@types/webpack": {
+      "version": "4.41.21",
+      "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.21.tgz",
+      "integrity": "sha512-2j9WVnNrr/8PLAB5csW44xzQSJwS26aOnICsP3pSGCEdsu6KYtfQ6QJsVUKHWRnm1bL7HziJsfh5fHqth87yKA==",
+      "dev": true,
+      "dependencies": {
+        "@types/anymatch": "*",
+        "@types/node": "*",
+        "@types/tapable": "*",
+        "@types/uglify-js": "*",
+        "@types/webpack-sources": "*",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/@types/webpack-sources": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-1.4.2.tgz",
+      "integrity": "sha512-77T++JyKow4BQB/m9O96n9d/UUHWLQHlcqXb9Vsf4F1+wKNrrlWNFPDLKNT92RJnCSL6CieTc+NDXtCVZswdTw==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/source-list-map": "*",
+        "source-map": "^0.7.3"
+      }
+    },
+    "node_modules/@types/webpack-sources/node_modules/source-map": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@types/ws": {
+      "version": "7.2.6",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.6.tgz",
+      "integrity": "sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/yargs": {
+      "version": "13.0.9",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz",
+      "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==",
+      "dev": true,
+      "dependencies": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "node_modules/@types/yargs-parser": {
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
+      "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
+      "dev": true
+    },
+    "node_modules/@types/zen-observable": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz",
+      "integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg==",
+      "dev": true
+    },
+    "node_modules/@vue/babel-helper-vue-jsx-merge-props": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz",
+      "integrity": "sha512-6tyf5Cqm4m6v7buITuwS+jHzPlIPxbFzEhXR5JGZpbrvOcp1hiQKckd305/3C7C36wFekNTQSxAtgeM0j0yoUw==",
+      "dev": true
+    },
+    "node_modules/@vue/babel-plugin-transform-vue-jsx": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.1.2.tgz",
+      "integrity": "sha512-YfdaoSMvD1nj7+DsrwfTvTnhDXI7bsuh+Y5qWwvQXlD24uLgnsoww3qbiZvWf/EoviZMrvqkqN4CBw0W3BWUTQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.0.0",
+        "@babel/plugin-syntax-jsx": "^7.2.0",
+        "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
+        "html-tags": "^2.0.0",
+        "lodash.kebabcase": "^4.1.1",
+        "svg-tags": "^1.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@vue/babel-preset-app": {
+      "version": "4.4.6",
+      "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.4.6.tgz",
+      "integrity": "sha512-urIa6Qk3lKacLvscrzxMNyYlTqKFcPAUo5MohOjv1ISZ9PssHw693WTOrqSC0XksdMLtp/rnLvc6l5G8Muk0lw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.9.6",
+        "@babel/helper-compilation-targets": "^7.9.6",
+        "@babel/helper-module-imports": "^7.8.3",
+        "@babel/plugin-proposal-class-properties": "^7.8.3",
+        "@babel/plugin-proposal-decorators": "^7.8.3",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+        "@babel/plugin-syntax-jsx": "^7.8.3",
+        "@babel/plugin-transform-runtime": "^7.9.6",
+        "@babel/preset-env": "^7.9.6",
+        "@babel/runtime": "^7.9.6",
+        "@vue/babel-preset-jsx": "^1.1.2",
+        "babel-plugin-dynamic-import-node": "^2.3.3",
+        "core-js": "^3.6.5",
+        "core-js-compat": "^3.6.5",
+        "semver": "^6.1.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "*",
+        "core-js": "^3"
+      },
+      "peerDependenciesMeta": {
+        "core-js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-preset-app/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@vue/babel-preset-jsx": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.1.2.tgz",
+      "integrity": "sha512-zDpVnFpeC9YXmvGIDSsKNdL7qCG2rA3gjywLYHPCKDT10erjxF4U+6ay9X6TW5fl4GsDlJp9bVfAVQAAVzxxvQ==",
+      "dev": true,
+      "dependencies": {
+        "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
+        "@vue/babel-plugin-transform-vue-jsx": "^1.1.2",
+        "@vue/babel-sugar-functional-vue": "^1.1.2",
+        "@vue/babel-sugar-inject-h": "^1.1.2",
+        "@vue/babel-sugar-v-model": "^1.1.2",
+        "@vue/babel-sugar-v-on": "^1.1.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
... 30882 lines suppressed ...